Archive for novembre, 2006

Servizi JMS transazionali in JBoss AS 4.x

Dopo aver tirato su i servizi JMS su JBoss AS 4.x, con tanto di MDB e MessageProducer, vediamo ora come inserire il tutto in un ambiente transazionale.

Quando arriva un nuovo messaggio sulla coda, l’MDB che è in ascolto riceve una chiamata onMessage() che inizia una nuova transazione JTA. Poniamo il caso che l’MDB debba eseguire una serie di operazioni in seguito all’arrivo del nuovo messaggio; se una di queste operazioni va in errore, l’MDB non deve scodare il messaggio (dare l’aknowledge) ma fare rollback dell’intero processo. Inoltre preferirei che il messaggio venga riproprosto dopo un tempo di attesa definito e per un numero massimo di tentativi.

Prima di tutto impostiamo il livello di transazione per l’MDB a RequiresNew per il metodo onMessage, in modo che all’arrivo di un nuovo messaggio il container inizi una nuova transazione:

ejb-jar.xml

<ejb-jar>
    <enterprise-beans>
    [...]
    </enterprise-beans>
    <assembly-descriptor>
        <container-transaction>
            <method>
                <ejb-name>MyMDBBean</ejb-name>
                <method-name>onMessage</method-name>
            </method>
            <trans-attribute>RequiresNew</trans-attribute>
        </container-transaction>
    </assembly-descriptor>
</ejb-jar>

L’interfaccia MessageDrivenContext deriva dalla EJBContext e ne nasconde quei metodi che nell’ottica dei MessageDrivenBean non hanno alcuna utilità (vd. getEJBHome(), getEJBLocalHome(), getCallerPrincipal() e isCallerInRole()). Il MessageDrivenContext rimane associata all’istanza del bean per tutto il ciclo della sua vita e ne rappresenta il legame con il container.

MyMDBBean.java

    [...]
    public void setMessageDrivenContext(MessageDrivenContext messageDrivenContext) throws EJBException {
        this.messageDrivenContext = messageDrivenContext;
    }

    public void onMessage(Message message) {
        logWriter.debug("---------- Start onMessage() -----------");
        logWriter.debug("Ricevuto nuovo messaggio nella coda");

        try {
            // do something...
        } catch (Exception ex) {
            logWriter.error("error: ", ex);
            messageDrivenContext.setRollbackOnly();
        }

        logWriter.debug("---------- End onMessage() -----------");
    }

Per legare la connessione con i servizi JMS alla transazione JTA occorre utilizzare la ConnectionFactory sotto il JNDI Name java:/JmsXA. Questa connection factory è l’unica a supportare JTA, mentre le altre connection factories (per es. ConnectionFactory) supportano solo le transazioni locali. Per far sì che il nostro MDB sia legato alla coda tramite suddetta ConnectionFactory occorre definirlo con i tag resource-ref in ejb-jar.xml e jboss.xml.

ejb-jar.xml

<ejb-jar>
    <enterprise-beans>
        <message-driven>
        [...]
            <resource-ref>
                <res-ref-name>jms/ConnectionFactory</res-ref-name>
                <res-type>javax.jms.ConnectionFactory</res-type>
                <res-auth>Container</res-auth>
            </resource-ref>
        </message-driven>
    </enterprise-beans>

    <assembly-descriptor>
    [...]
    </assembly-descriptor>
</ejb-jar>

jboss.xml

<jboss>
    <enterprise-beans>
        <message-driven>
        [...]
            <resource-ref>
                <res-ref-name>jms/ConnectionFactory</res-ref-name>
                <jndi-name>java:/JmsXA</jndi-name>
            </resource-ref>
        </message-driven>
    </enterprise-beans>
</jboss>

Se siete fortunati ed utilizzate EJB 3.0, la specifica prevede la seguente annotation:

@Resource(mappedName="java:/JmsXA")
ConnectionFactory connFactory;

Infine occorre gestire la ritrasmissione dei messaggi in caso di errore. Per far ciò è necessario aggiungere dei parametri alla configurazione della coda.

myapp-destinations-service.xml

<server>
    <mbean code="org.jboss.mq.server.jmx.Queue" name="jboss.mq.destination:service=Queue,name=MyQueue">
        <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
        <depends optional-attribute-name="SecurityManager">jboss.mq:service=SecurityManager</depends>

        <attribute name="MessageCounterHistoryDayLimit">-1</attribute>
        <attribute name="RedeliveryLimit">3</attribute>
        <attribute name="RedeliveryDelay">300000</attribute> <!-- 5 min -->

    </mbean>
</server>

Il parametro “RedeliveryLimit” indica i tentativi di re-inoltro del messaggio prima di settarlo completamente in errore e spedirlo nella coda standard DLQ (Dead Letter Queue). Il parametro “RedeliveryDelay” indica il tempo (in msec) da attendere prima di ritentare l’inoltro di un messaggio precedentemente andato in errore.

…e anche questa è andata.

novembre 2, 2006 at 10:43 am 3 commenti


Calendario

novembre: 2006
L M M G V S D
 12345
6789101112
13141516171819
20212223242526
27282930  

Posts by Month

Posts by Category