MokaByte 67 - 8bre 2002 
Java Connector Architecture
II parte: CCI teoria
di
S.Rossini
G.Morello
Per accedere da un'applicazione J2EE ad un Resource Adapter (RA), l'architettura JCA mette a disposizione delle API denominate CCI (Common Client Interface). In questo articolo si effettuerą una panoramica sulle API CCI

COMMON CLIENT INTERFACE (CCI)
CCI definisce un insieme di API per uniformare l'accesso ad EIS da parte di applicazioni client. I client CCI possono essere componenti applicativi quali EJB o componenti d'integrazione come gli stessi Integration Broker.

CCI fornisce API di alto livello che permettono di astrarsi dai dettagli e dalle specificità di gestione delle differenti risorse EIS, operando rispetto a queste in modo analogo a JDBC rispetto ai DBMS, JMS rispetto ai sistemi di messaging o JNDI rispetto ai servizi di Naming e Directory.

L'analogia è ancora più stretta se si confronta JCA con JDBC; si può scherzosamente affermare che JCA è il "cugino di primo grado" [BSTW] di JDBC.

Le API CCI astraggono lo sviluppatore dai dettagli di comunicazione con lo specifico EIS e definiscono uno standard per accedere a qualsiasi EIS non-relazionale. In modo similare, le API JDBC astraggono lo sviluppatore dai dettagli di comunicazione con lo specifico DBMS e definiscono uno standard per accedere a database relazionali.


Per creare una connessione con JDBC si utilizza javax.sql.DataSource,

dataSource = (DataSource) ic.lookup("java:comp/env/jdbc/MyDataBase");

in JCA si utilizza javax.resource.cci.ConnectionFactory

factoryJCA = (ConnectionFactory) ic.lookup("java:comp/env/eis/MyHost");

Per ottenere una connesione con il DBMS in JDBC si utilizza il metodo getConnection dell'oggetto DataSource
java.sql.Connection con = dataSource.getConnection();
in JCA avviene in modo analogo, invocando il metodo getConnection sull'oggetto ConnectionFactory
javax.resource.cci.Connection con = cf.getConnection(. . .);
Come già detto in [JCA1] l'implementazione delle API CCI non è mandataria. Se l'accesso via CCI non è disponibile, è necessario utilizzare direttamente l'interfaccia proprietaria del RA; ovviamente l'utilizzo diretto di API proprietarie riduce i vantaggi di astrazione di JCA.
PANORAMICA API CCI
Le API CCI si dividono fondamentalmente in quattro aree :

  • Connection API: per connettersi all'EIS
  • Interaction API: per eseguire comandi ed invocare azioni sull'EIS
  • Record/ResultSet API: incapsulano il risultato dell'operazione avvenuta sull'EIS
  • Metadata API: che permettono la descrizione dei tipi di dati

Affinchè un RA sia CCI-compliant deve implementare un set di intefacce (presentate nel seguito).
Le interfacce obbligatorie da implementare sono javax.resource.cci.Connection e javax.resource.cci.Interaction.
Le API CCI sono costituite da sole interfacce, incluse nel package javax.resource.cci.



clicca per ingrandire


ConnectionFactory (javax.resource.cci.ConnectionFactory)
E' l'interfaccia Factory responsabile della creazione delle connessioni con l'EIS. Il ConnectionFactory è pubblicato in un namespace JNDI e quindi reperibile mediante l'operazione JNDI di lookup.

ConnectionFactory cf = (ConnectionFactory)
context.lookup("java:comp/env/eis/CCI_MOKA_EIS");

Un componente J2EE per ottenere la connessione con l'EIS deve invocare il metodo getConnection del ConnectionFactory.


Connection CONNECTION (javax.resource.cci.Connection)
Rappresenta la connessione con il sottosistema EIS. La Connection si ottiene invocando il metodo getConnection su un'istanza di ConnectionFactory.

Connection con = cf.getConnection(spec);

Permette inoltre di creare un oggetto Interaction per interagire con la risorsa EIS.

Interaction ix = con.createInteraction();

Il metodo close permette di chiudere la connessione con l'EIS.

try { con.close();}
catch (ResourceException ex) {. . .}

ConnectionMetadata (javax.resource.cci.ConnectionMetaData)
Permette di specificare le informazioni sull'istanza EIS puntata dal Connection reference. I metadata sono ottenibili invocando il metodo getMetaData sull'oggetto Connection.

MokaCciConnectionMetaData conMetaData =
(MokaCciConnectionMetaData)con.getMetaData();


System.out.println("EISProductName="+
                    conMetaData.getEISProductName());
System.out.println("ProductVersion="+
                    conMetaData.getEISProductVersion());
System.out.println("UsertName ="+
                    conMetaData.getUserName());

ConnectionSpec (javax.resource.cci.Connection)
L'implementazione di questa interfaccia permette al client di comunicare al ConnectionFactory eventuali proprietà specifiche (request-specific properties ) della risorsa EIS durante la richiesta di connessione.

Questa classe è di fatto un Java bean con proprietà, metodi di accesso (mutators methods-setter) e metodi di lettura (accessors methods-getter).

ConnectionSpec spec = new CciConnectionSpec(user, password);
Connection con = connectionFactory.getConnection(spec);

ResourceAdapterMetaData (javax.resource.cci.ResourceAdapterMetadata)
E' l'interfaccia che fornisce informazioni sulle caratteristiche del Resource Adapter. E' ottenibile invocando il metodo getMetaData sull'oggetto ConnectionFactory.
Tale invocazione quindi non implica che sia attiva una connessione con la risorsa EIS in quanto si limita a fornire informazioni descrittive e di utilizzo del RA.

MokaCciResourceAdapterMetaData raMetaData =
(MokaCciResourceAdapterMetaData)cf.getMetaData();
System.out.println(raMetaData.getAdapterName());
System.out.println(raMetaData.getAdapterShortDescription());
System.out.println(raMetaData.getAdapterVendorName());
System.out.println(raMetaData.getAdapterVersion());
System.out.println(raMetaData.getInteractionSpecsSupported());
System.out.println(raMetaData.getSpecVersion());
System.out.println(raMetaData.
                   supportsExecuteWithInputAndOutputRecord());
System.out.println(raMetaData.
                   supportsExecuteWithInputRecordOnly()); System.out.println(raMetaData.
                   supportsLocalTransactionDemarcation());


InteractionSpec (javax.resource.cci.InteractionSpec)
Contiene le eventuali proprietà necessarie per interagire con la risorsa EIS. E' utilizzata dall'oggetto Interaction per l'esecuzione della specifica funzione della risorsa EIS.
Come il ConnectionSpec, anche l'InteractionSpec è di fatto un Java Bean.

CciInteractionSpec iSpec = new CciInteractionSpec();
iSpec.setFunctionName("WRITE");
ecc …

Interaction (javax.resource.cci.Interaction)
Permette di interagire con la risorsa EIS indicando la modalità d'accesso(scrittura/lettura). L'oggetto Interaction viene costruito a partire dall'oggetto Connection.

Interaction ix = con.createInteraction();

Il metodo close chiude l'interaction corrente e rilascia tutte le risorse associate ma non la connessione con l'EIS. E' buona pratica invocare in modo esplicito il metodo close alla fine di ogni interazione.

ix.close();

L'interazione con la risorsa EIS avviene mediante il metodo execute fornito con le seguenti firme:

public boolean execute(InteractionSpec ispec,Record input,
                       Record output) throws ResourceException

esegue l'interazione con la risorsa EIS aggiornando il valore dell'output Record restituendo true se l'operazione è andata a buon fine. Se l'interazione fallisce il metodo solleva una javax.resource.ResourceException.

public Record execute(InteractionSpec ispec, Record input)
throws ResourceException

esegue l'interazione con la risorsa EIS ricevendo in ingresso un Record e restituendo come output un nuovo Record nel caso l'operazione abbia successo.

Record (javax.resource.cci.Record
E' l'interfaccia madre delle varie tipologie di Record. Rappresenta i dati di input e output necessari per eseguire le interazioni con l'EIS.
Esempi di interfacce derivate sono:

  • MappedRecord: record di coppie di chiave-valore basati sull'interfaccia java.util.Map
  • IndexedRecord: collezione ordinata ed accessibile mediante indice
  • ResultSet: estende sia l'interfaccia Record, sia l'interfaccia java.sql.ResultSet per reperire dati in forma tabellare.

E' inoltre possibile creare una propria tipologia di Record in funzione delle esigenze specifiche dell'EIS (es: un Record per rappresentare un ordine di acquisto presso un sistema ERP).

RecordFactory (javax.resource.cci.RecordFactory)
E' l'interfaccia factory responsabile della creazione d'istanze di Record. Così come il ConnectionFactory permette di avere oggetti Connection, il RecordFactory permette di ottenere oggetti Record.
Mette a disposizione un metodo factory specifico per ogni tipologia di record (createIndexedRecord, createMappedRecord, createResultSet).

LocalTransaction ( javax.resource.cci.resourceAdapterMetaData)
E' l'interfaccia utilizzata per demarcare (begin, commit e rollback) le transazioni locali ad un RA. La gestione della local transaction è interna al RA e non coinvolge nessun coordinamento esterno.
Un'istanza valida di LocalTransaction è ottenibile, se l'implementazione CCI lo supporta, invocando il metodo Connection.getLocalTransaction.

 

Come utilizzare un connettore
Dopo la panoramica delle API CCI, vediamo come un client J2EE può accedere ad un RA.
Le operazioni che devono essere effettuate sono:

Importare il package javax.resource.CCI, la classe javax.resource.ResourceException e le classi relative al connettore da utilizzare

import javax.resource.cci.*;
import javax.resource.ResourceException;
import it.mokabyte.mokajca.ra.*;

Effettuare, mediante JNDI, la lookup dell'oggetto ConnectionFactory del Resource Adapter

Context ctx = new InitialContext();
Object obj = ctx.lookup("java:comp/env/eis/CCI_MOKA_EIS");

effettuando l'opportuno downcast

ConnectionFactory cf = (ConnectionFactory)obj;

Creare l'oggetto ConnectionSpec per indicare gli eventuali parametri specifici necessari ad ottenere la conessione all'EIS

ConnectionSpec spec = new CciConnectionSpec(
                          <<param1>>,. . .,<<paramN>>);

Invocare sull'oggetto ConnectionFactory il metodo getConnection per ottenere l'apertura della connessione con il Resource Manager dell'EIS

Connection con = cf.getConnection(spec);

L'oggetto Connection rappresenta la connessione con l'EIS e permette di interagire con la risorsa stessa.
Invocare sull'oggetto Connection il metodo createInteraction per creare un'istanza Interaction. Mediante l'istanza ottenuta sarà possibile interagire con la risorsa EIS

Interaction ix = con.createInteraction();

Per specificare eventuali parametri specifici per interagire con la risorsa EIS (ad esempio per indicare il nome di una tabella da accedere, il nome di un transazione, i parametri dell'operazione ecc…) si utilizza l'oggetto InteractionSpec

CciInteractionSpec iSpec = new CciInteractionSpec();
iSpec.setFunctionName("WRITE_TO_MY_EIS");


Creare RecordFactory invocando il metodo getRecordFactory sull'oggetto ConnectionFactory.

RecordFactory rf = cf.getRecordFactory();


Utilizzare l'oggetto RecordFactory per costruire gli appropriati record di lettura e/o scrittura. Tali record possono essere di input, output o sia di input che di output ( Record inout)

IndexedRecord iRec = rf.createIndexedRecord("InputRecord");
iRec.add(new Integer(userid));
iRec.add(username);
Record oRec = null; // Ouput Record

Eseguire le opportune operazioni sul Data Store invocando il metodo execute sull'oggetto Interaction fornendo gli opportuni Record di input, di output o di inout

Record oRec = ix.execute(iSpec, iRec);
Iterator iterator = ((IndexedRecord)oRec).iterator();
while(iterator.hasNext()) {
  Object obj = iterator.next();
  . . .
}

oppure

if(ix.execute(iSpec, iRec, oRec)) {
  // success
}
else {
  // failed
}

Conclusa la comunicazione con la risorsa EIS è necessario effettuare il codice di chiusura invocando sull'oggetto Connection il metodo close

con.close();

L'immagine seguente riporta il sequence diagram delle operazioni descritte.


clicca per ingrandire

Se il RA supporta la gestione delle transazioni, prima di iniziare l'interazione con la risorsa EIS si deve demarcare l'inizio della transazione

// ottengo un reference al transaction context
LocalTransaction transaction = con.getLocalTransaction();
// avvio della transazione
transaction.begin();

Cocnclusa l'operazione si deve gestire la commit se l'operazione ha avuto successo o la rollback in caso si siano rilevati errori

...
try {
ix.execute(iSpec, iRec);
transaction.commit();
} catch (ResourceException e) {
transaction.rollback();
}
// Close the connection
...


Conclusioni
In questo articolo abbiamo analizzato le API CCI. Nella prossima puntata introdurremo un semplice connettore implementato e pensato per scopi didattici: il MokaConnector. Verrà presentata l'implementazione della classi CCI del MokaConnector.

 

Bibliografia e riferimenti
[JCA1] G.Morello - S.Rossini: "Java Connector Architecture", Mokabyte N.66 - Settembre 2002

[JCA] http://java.sun.com/j2ee/connector/

[SPEC] J2EE Connector Architecture Specification, http://java.sun.com/j2ee/download.html#connectorspec

[CCI1] Beth Stearns: Using the J2EETM Connector Architecture Common Client Interface, http://java.sun.com,Aprile 2001

[BSTW] David Marks: J2EE Connector Architecture Brings Business Systems to the web,
http://developer.java.sun.com/developer/technicalArticles/J2EE/
connectorclient/resourceadapter.html

[JW2] Dirk Reinshagen: Connect the enterprise with the JCA, Part 2,JavaWorld Febbraio 2002

[JROD] Jennifer Rodoni: The Java 2 Enterprise Edition Connector Architecture's Resource Adapter, http://developer.java.sun.com/developer/technicalArticles/
                                                         J2EE/connectorclient/resourceadapter.html

[JTUT] J2EE Tutorial, http://java.sun.com/j2ee/tutorial/download.html : esample of black box resource adapter for J2EE reference implementation.

[JBOSS] http://www.jboss.org

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it