Introdução aos Slots de Plug-in

Um slot de plug-in é um espaço de armazenamento transacional reservado para os plug-ins que compartilham o contexto transacional. Estes slots fornecem uma forma para os plug-ins do eXtreme Scale se comunicarem um com o outro, compartilhar contexto transacional e assegurar que os recursos transacionais sejam usados correta e consistentemente dentro de uma transação.

Um plug-in pode armazenar o contexto transacional, como a conexão com o banco de dados, a conexão com o JMS (Java Message Service), e assim por diante, em um slot de plug-ins. O contexto transacional armazenado pode ser recuperado por qualquer plug-in que conheça o número do slot do plug-in, o qual serve como chave para recuperar o contexto transacional.

Utilizando Slots de Plug-in

Os slots de plug-in são parte da Interface TxID. Consulte a Documentação da API para obter mais informações sobre a interface.Os slots são entradas em uma matriz ArrayList. Os plug-ins podem reservar uma entrada na matriz ArrayList ao chamar o método ObjectGrid.reserveSlot e indicar que requer um slot em todos os objetos TxID. Após reservar os slots, os plug-ins podem inserir um contexto transacional nos slots de cada objeto TxID e recuperá-lo posteriormente. As operações put e get são coordenadas pelos números de slot que são retornados pelo método ObjectGrid.reserveSlot.

Um plug-in normalmente tem um ciclo de vida. A utilização dos slots de plug-in deve se adequar ao ciclo de vida do plug-in. Normalmente, o plug-in deve reservar slots de plug-in durante o estágio de inicialização e obter os números de cada slot. Durante o tempo de execução normal, o plug-in insere contexto transacional no slot reservado no objeto TxID no ponto apropriado. Normalmente, esse ponto apropriado é o início da transação. O plug-in ou outros plug-ins podem, desse modo, obter o contexto provisório armazenado pelo número de slot do TxID dentro da transação.

O plug-in tipicamente executa uma limpeza por meio da remoção do contexto transacional e dos slots. O fragmento de código a seguir ilustra como utilizar os slots de plug-in em um plug-in TransactionCallback:

public class DatabaseTransactionCallback implements TransactionCallback {
    int connectionSlot;
    int autoCommitConnectionSlot;
    int psCacheSlot;
    Properties ivProperties = new Properties();

    public void initialize(ObjectGrid objectGrid) throws TransactionCallbackException {
        // In initialization stage, reserve desired plug-in slots by calling the 
        //reserveSlot method of ObjectGrid and
        // passing in the designated slot name, TxID.SLOT_NAME.
        // Note: you have to pass in this TxID.SLOT_NAME that is designated 
        // for application.
        try {
            // cache the returned slot numbers
            connectionSlot = objectGrid.reserveSlot(TxID.SLOT_NAME);
            psCacheSlot = objectGrid.reserveSlot(TxID.SLOT_NAME);
            autoCommitConnectionSlot = objectGrid.reserveSlot(TxID.SLOT_NAME);
        } catch(Exception e) {
        }
    }

    public void begin(TxID tx) throws TransactionCallbackException {
        // put transactional contexts into the reserved slots at the 
        // beginning of the transaction.
        try {
            Connection conn = null;
            conn = DriverManager.getConnection(ivDriverUrl, ivProperties);
            tx.putSlot(connectionSlot, conn);
            conn = DriverManager.getConnection(ivDriverUrl, ivProperties);
            conn.setAutoCommit(true);
            tx.putSlot(autoCommitConnectionSlot, conn);
            tx.putSlot(psCacheSlot, new HashMap());
        } catch (SQLException e) {
            SQLException ex = getLastSQLException(e);
            throw new TransactionCallbackException("unable to get connection", ex);
        }
    }

    public void commit(TxID id) throws TransactionCallbackException {
        // get the stored transactional contexts and use them
        // then, clean up all transactional resources.
        try {
            Connection conn = (Connection) id.getSlot(connectionSlot);
            conn.commit();
            cleanUpSlots(id);
        } catch (SQLException e) {
            SQLException ex = getLastSQLException(e);
            throw new TransactionCallbackException("commit failure", ex);
        }
    }

    void cleanUpSlots(TxID tx) throws TransactionCallbackException {
        closePreparedStatements((Map) tx.getSlot(psCacheSlot));
        closeConnection((Connection) tx.getSlot(connectionSlot));
        closeConnection((Connection) tx.getSlot(autoCommitConnectionSlot));
    }

    /**
     * @param map
     */
    private void closePreparedStatements(Map psCache) {
        try {
            Collection statements = psCache.values();
            Iterator iter = statements.iterator();
            while (iter.hasNext()) {
                PreparedStatement stmt = (PreparedStatement) iter.next();
                stmt.close();
            }
        } catch (Throwable e) {
        }

    }

    /**
     * Close connection and swallow any Throwable that occurs.
     *
     * @param connection
     */
    private void closeConnection(Connection connection) {
        try {
            connection.close();
        } catch (Throwable e1) {
        }
    }

    public void rollback(TxID id) throws TransactionCallbackException
        // get the stored transactional contexts and use them
        // then, clean up all transactional resources.
        try {
            Connection conn = (Connection) id.getSlot(connectionSlot);
            conn.rollback();
            cleanUpSlots(id);
        } catch (SQLException e) {
        }
    }

    public boolean isExternalTransactionActive(Session session) {
        return false;
    }

    // Getter methods for the slot numbers, other plug-in can obtain the slot numbers 
    // from these getter methods.

    public int getConnectionSlot() {
        return connectionSlot;
    }
    public int getAutoCommitConnectionSlot() {
        return autoCommitConnectionSlot;
    }
    public int getPreparedStatementSlot() {
        return psCacheSlot;
    }

O fragmento de código a seguir ilustra como um Utilitário de Carga pode obter o contexto transacional armazenado inserido pelo exemplo de plug-in TransactionCallback anterior:

public class DatabaseLoader implements Loader
{
    DatabaseTransactionCallback tcb;
    public void preloadMap(Session session, BackingMap backingMap) throws LoaderException {
        // The preload method is the initialization method of the Loader.
        // Obtain interested plug-in from Session or ObjectGrid instance.
        tcb = (DatabaseTransactionCallback)session.getObjectGrid().getTransactionCallback();
    }
    public List get(TxID txid, List keyList, boolean forUpdate) throws LoaderException
    {
        // get the stored transactional contexts that is put by tcb's begin method.
        Connection conn = (Connection)txid.getSlot(tcb.getConnectionSlot());
        // implement get here
        return null;
    }
    public void batchUpdate(TxID txid, LogSequence sequence) 
	throws LoaderException, OptimisticCollisionException
    {
        // get the stored transactional contexts that is put by tcb's begin method.
        Connection conn = (Connection)txid.getSlot(tcb.getConnectionSlot());
        // implement batch update here ...
    }
}