Definizione
del problema
Il primo problema che è necessario affrontare nell'ambito
dell'integrazione è essenzialmente di comunicazione.
Sia che si operi in modalità punto-punto (vedi [MOKA_INT6])
sia che si adotti una visione centralizzata (vedi [MOKA_EAI_IM]),
il problema principale è la normalizzazione del protocollo
specifico della risorsa con un'interfaccia fruibile dal chiamante.
Tale
problematica viene tipicamente affrontato attraverso componenti
denominati genericamente Adapter. Nel caso specifico di Adapter
destinati alla comunicazione con risorse Enterprise Information
Systems (EIS), vengono più precisamente detti Resource
Adapter (RA).
Nella
serie di articoli di Mokabyte apparsi sui numeri di Mokabyte
(vedere [MOKA_JCA1] e successivi) si è parlato di JCA
sia da un punto di vista architetturale che da un punto di
vista pratico presentando un esempio di Resource Adapter:
il MokaConnector.
In
questo articolo si metterà a frutto l'esperienza acquisita
nei precedenti numeri per capire come utilizzare un connettore
JCA per invocare un programma Cobol via CICS ECI.
Il
Resource Adapter
Il RA è un componente che espone delle interfacce di
accesso (client API) per permettere la comunicazione, sincrona
o asincrona, con la corrispondente risorsa EIS come sistemi
Legacy (CICS,IMS,3270,
), basi dati relazionali (Oracle,
SQLServer, MySQL,...) e non (Lotus Notes), sistemi ERP (Enterprise
Resource Planning),sistemi CRM (Customer Relationship Management).
Il RA ha quindi il duplice scopo di:
- fornire
un'interfaccia omogenea ai client per accedere all'EIS
- mascherare
la complessità dell'interazione con l'EIS al client
Figura 1 : Il Resource Adapter
Cos'è
JCA?
JCA è l'acronimo di Java Connector Architecture. Definisce
un'architettura standard (vedere [JCA_SPEC]) per uniformare
l'accesso ad EIS eterogenei all'interno di applicazioni J2EE.
Si focalizza sul design di Adapter software destinati a connettere
applicazioni J2EE con applicazioni non-Java come risorse legacy
e pacchetti applicativi.
L'architettura
JCA è costituita da tre elementi : le API Common Client
Interface (CCI), i Resource Adapter ed i System Contracts.
Figura 2 : L'architettura JCA
Vediamo una breve descrizione dei componenti dell'architettura
JCA (per una maggiore trattazione si rimanda a [MOKABOOK2_JCA]).
CCI
definisce un insieme di API per uniformare l'accesso a EIS
da parte di applicazioni J2EE. Grazie a CCI non è necessario
affrontare un'integrazione ad hoc per ogni diversa tipologia
di EIS, analogamente a quanto avviene con JDBC, JNDI e JMS.
Il Resource Adapter è il connettore vero e proprio,
cioè è il driver software che permette al client
(sia esso un componente J2EE come un EJB o l'Application Server
stesso) di connettersi fisicamente alla risorsa EIS.
Figura 3 : Esempi di connettori JCA
Un
Resource Adapter JCA interagisce con le infrastrutture del
server J2EE tramite i cosiddetti System Contracts (Connection,
Transaction e Security ).
Il Connection Management determina le politiche per stabilire/chiudere
le connessioni con le risorse di Backend ottimizzando la gestione
degli accessi mediante un Connection Pool gestito dall'Application
Server.
Il Transaction Management permette di gestire l'accesso transazionale
verso le risorse EIS, definendo le interazioni tra la risorsa
ed il transaction manager.
Le transazioni possono richiedere la presenza di un Transaction
Manager esterno oppure possono essere gestite internamente
dal Resource Manager della risorsa stessa.
Il Security contract definisce un contratto che permette di
gestire la Sicurezza per accedere all'EIS. Consente allo sviluppatore
del RA di implementare/fornire i meccanismi per la gestione
dell'autenticazione e dell'autorizzazione, ed eventualmente
consente la gestione di un security environment custom per
la comunicazione sicura tra il server J2EE e l'EIS.
Il
RA è contenuto in un file archivio (jar) di estensione
RAR (Resource Adapter Archive) composto dai file Java e dalle
eventuali librerie native necessarie per accedere alla risorsa
EIS. Un file .rar rappresenta a tutti gli effetti una risorsa
J2EE e può essere installato singolarmente o all'interno
di un file .ear. Ogni RA è "accompagnato"
da un file deployment descriptor di nome ra.xml posizionato
sotto la directory METAINF (METAINF/ra.xml).
Il deployment descriptor contiene le informazionidel RA quali
il nome, le interfacce e relative classi concrete per accedere
al connettore, il tipo di supporto Transazionale, le informazioni
di autenticazione, le proprietà di configurazione,
cioè tutte le informazioni necessarie per effettuare
sia il deploy che la configurazione del RA per un Application
Server JCA-enabled.
Una
volta creato il file RAR è possibile effettuare l'operazione
di deploy del RA in un server J2EE, analogamente a quanto
accade per gli EJB jar, i file war o gli stessi file ear.
Come
connettersi a CICS con un Resource Adapter JCA
E veniamo al nocciolo dell'articolo. Negli articoli [MOKA_JCA_3]
e [MOKA_JCA_5] si era presentato il MokaConnnector, un resource
adapter CCI-compliant che si connette ad una risorsa EIS rappresentata
da un file testuale. Il MokaConnector permette a componenti
J2EE un accesso standard mediante le API CCI descritte in
[MOKA_JCA_2]. Per motivi didattici, il MokaConnector non si
concentra sulle problematiche specifiche dell'accesso a risorse
EIS complesse, ma gestisce un semplice file testuale
La
SUN nel J2EE Tutorial (vedere [JTUT]) presenta un esempio
di connettore JCA (anch'esso CCI compliant) che permette di
invocare Stored Procedure per Cloudscape denominato "CCI
black box".
Per
usare un connettore JCA (CCI-compliant) bisogna effettuare
una serie di operazioni in modo pragmatico (vedere [MOKA_JCA2])
come schematizzato nella figura che segue:
Figura 4 : utilizzo delle API CCI
Supponiamo
di doverci collegare ad un programma Cobol via CICS-ECI utilizzando
un connettore JCA.
Il
CICS (Customer Information Control System ) è un TP
monitor che permette di eseguire transazioni a HOST. L'interfaccia
CICS ECI (External Call Interface) permette di eseguire, da
un'applicazione esterna nonCICS, un progamma CICS su un server
CICS come se il chiamante fosse un programma Cobol all'interno
del suo stesso ambiente ed eseguisse un comando EXEC CICS
LINK.
Per
fare questo useremo il connettore JCA per IBM CICS della ditta
Comporsys Hansa GmbH (vedere [COMPORSYS]), liberamente scaricabile
da Internet (vedere [COMPORSYS_DWLD]).
Il
connettore Comporsys supporta JCA 1.0, mette a disposizione
un'interfaccia CCI e permette di invocare programmi CICS via
ECI.
Figura 5 : Scenario CICS
Avendo
letto l'articolo di come utilizzare il Moka Connector (vedere
[MOKA_JCA3]) e/o il connettori del Tutorial SUN, cosa ci dobbiamo
aspettare?
Ci dobbiamo aspettare di riutilizzare gran parte del codice
client già usato con gli altri due connettori JCA (essendo
CCI-Compliant!) e modificare le parti di codice che utilizzano
le classi dipendenti dalla specfica risorsa EIS.
Quindi dovremmo avere che le seguenti operazioni siano le
medesime indipendentemente dal RA (sia esso un RA per DBMS,
Host, file,
)
- Lookup
dell'oggetto ConnectionFactory del Resource Adapter mediante
API JNDI
Context
ctx = new InitialContext();
Object obj = ctx.lookup("java:comp/env/eis/CCI_MOKA_EIS");
ConnectionFactory cf = (ConnectionFactory)obj;
- invocazione
del metodo ConnectionFactory.getConnection() per ottenere
l'apertura della connessione con il Resource Manager dell'EIS
passando come parametro un oggetto ConnectionSpec:
Connection
con = cf.getConnection(connSpec);
- invocazione
sull'oggetto Connection (la connessione con l'EIS ) del
metodo createInteraction() per creare un'istanza
Interaction.
Mediante l'istanza ottenuta sarà possibile interagire
con la risorsa EIS
Interaction ix = con.createInteraction();
- creazione
del RecordFactory invocando il metodo ConnectionFactory
getRecordFactory()
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");
- Invocazione
del metodo execute sull'oggetto Interaction.execute() fornendo
gli opportuni Record di input, di output (o di inout) e
un'istanza InteractionSpec
if(ix.execute(interSpec,
iRec, oRec)) {
// Recupero del risultato ...
risultato=oRec.getXXX()
//
... o eventuale iterazione nel caso di liste di risultati
Iterator
iterator = ((IndexedRecord)oRec).iterator();
while(iterator.hasNext())
{
Object
obj = iterator.next();
...
}
}
else {
//
failed
}
- Chiusura
della connessione con l'EIS
con.close();
Quello
che cambierà nell'interazione della specifica risorsa
EIS sono le classi ConnectionSpec e InteractionSpec che sono
classi specifiche per la risorse EIS.
Figura 6 : API CCI
L'oggetto ConnectionSpec (che implementa l'interfaccia javax.resource.cci.ConnectionSpec)
permette di indicare gli eventuali parametri specifici necessari
ad ottenere la conessione all'EIS)
Ad
esempio per il MokaConnector si specificare un'utenza
MokaCciConnectionSpec
connSpec = new MokaCciConnectionSpec("mokabyte");
mentre
nel caso del RA Sun si deve indicare username e password per
accedere a DB
ConnectionSpec
connSpec = new CciConnectionSpec(user, password);
Per
indicare eventuali parametri specifici per interagire con
la risorsa EIS si deve utilizzare l'oggetto InteractionSpec
(che implementa l'interfaccia javax.resource.cci.InteractionSpec)
Ad
esempio per il MokaConnector si indicava l'operazione (lettura/scrittura
del file) e il numero di linee del file coinvolte:
CciInteractionSpec
interSpec = new CciInteractionSpec();
iSpec.setFunctionName(MokaCciInteractionSpec.READ);
iSpec.setNumOfLines(num);
mentre
nel caso del RA Sun si deve specificare il nome della Stored
procedure da invocare ed il relativo Schema e Catalog:
CciInteractionSpec
interSpec = new CciInteractionSpec();
iSpec.setFunctionName("INSERTCOFFEE");
iSpec.setSchema(user);
iSpec.setCatalog(null);
Ci
si deve quindi concentrare sul capire quali sono le classi
del Connecttore Comporsys specifiche per accedere a Host via
CICS-ECI.
Da
notare come a seconda della specifica esigenza di I/O con
la risorsa EIS è possibile implementare una propria
classe Record che deve implementare l'interfaccia javax.resource.cci.Record.
Tale classe può mettere quindi a disposizione gli opportuni
metodi puntuali per il set dei dati di input ed il get dei
dati di output. Ma
procediamo per gradi
Il
programma Cobol che si vuole invocare esegue un semplice calcolo
computazionale che prevede di restituire la lunghezza (WS-COUNTER)
della stringa (WS-STRINGA) fornitagli in ingresso.
Analizzando
la COMMAREA del programma Cobol si vede che è prevista
una stringa di 30 caratteri (PICX(30)) come dato in ingresso
e un numero di 10 cifre (s9(10)) come dato in uscita:
01
COMMAREA
03 WS-STRINGA PIC X(30).
03 WS-COUNTER PIC 9(10).
Figura
7: Scenario Host: Programma Cobol & COMMAREA
Una transazione CICS è strutturata in modo da condividere
un'area di memoria per il passaggio dei dati (input e output)
esterni al programma.
Questa area comune di memoria (di dimensione fissa di 32K)
è denominata COMMAREA e serve per il transito dei dati
verso/da CICS e quindi nella sua definizione si trovano sia
i campi di input che di output.
Il sistema CICS riceve i dall'esterno e passa i dati di input
della COMMAREA al programma Cobol associato alla transazione.
Finita l'elaborazione del programma Cobol, i dati di output
verranno scritti dall'applicazione COBOL nella COMMAREA ed
il CICS provvederà a veicolarli verso il programma
esterno chiamante.
Con
il RA Comporsys si ha a disposizione un utility chiamata CodeGen
che permette, a partire da una CopyCobol descritta in un file
di estensione .cob, di creare classi Java che mappano la COMMAREA
del programma Cobol convertendo i tipi da Cobol a Java.
Queste classi saranno i Record contenente i dati da scambiarsi
(input e output) con CICS.
Bisogna
quindi mandare in esecuzione la classe de.comporsys.codegen.ImportCobol
specificando il file Cobol in ingresso (mokarecord.cob), la
directory di ouput, il nome del package (it.mokabyte.jca.cicseci)
ed il codepage.
java
de.comporsys.codegen.ImportCobol mokarecord.cob classes it.mokabyte.jca.cicseci
cp273
Quello
che si ottiene è la classe MOKARECORD. Mediante il
metodo setWS-STRINGA(), sarà possibile specificare
il dato di input e ottenere la relativa lunghezza tramite
il metodo getWS-COUNTER():
public
class MOKARECORD extends Record implements java.io.Serializable{
static final MOKARECORDDescription description
= new MOKARECORDDescription() ;
public static class MOKARECORDDescription extends
de.comporsys.connector.datatype.Description implements
java.io.Serializable{
final de.comporsys.connector.datatype.cobol.X
ws_stringa ;
final de.comporsys.connector.datatype.cobol.Nine
ws_counter ;
public MOKARECORDDescription( ){
super() ;
ws_stringa = new X( new PicClause(
"X(30)" )) ;
ws_counter = new Nine( new PicClause(
"9(10)" )) ;
...
}
public MOKARECORD(){
super(description ) ;
description.setName( "MOKARECORD"
) ;
}
public
String getWS_STRINGA() {
return description.ws_stringa.getValue(
this ).toString() ;
}
public
void setWS_STRINGA( String value ){
description.ws_stringa.setValue( value,
this ) ;
}
public long getWS_COUNTER(){
return description.ws_counter.longValue(
this ) ;
}
public
void setWS_COUNTER( long value ){
description.ws_counter.setValue( value,
this ) ;
}
...
}
Figura 8: Generazione del Record I/O per COMMAREA CICS
Nel
file ra.xml, il file deployment descriptor del RA (vedere
[MOKA_JCA4]) bisogna inserire, mediante il tag <config-property>,
i valori delle proprietà del RA necessari per collegarsi
al CICS Server. Le principali informazioni del RA Comporsys
CICS sono:
- ServerName:
nome del server CICS
- ConnectionURL:
indirizzo del server CTG (es: tcp://localhost:2007)
- CCISupport:
supporto API CCI (nostro caso è true)
- TimeoutSecs:
timeout di connessione
- UserName,
Password: utenza di accesso a Host
Si
vede come per accedere a Host si deve specificare un indirizzo
tcp. A cosa si riferisce tale indirizzo? L'indirizzo si riferisce
al CICS Transaction Gateway (CTG) grazie al quale sarà
possibile accedere al CICS Server.
Il connettore COMPORSYS di fatto espone, mediante API CCI,
l'utilizzo delle classi Java IBM client del CTG.
Il
CTG rappresenta il connettore strategico fornito da IBM per
abilitare il dialogo con le applicazioni CICS. Il prodotto
supporta la tecnologia J2EE, implementa lo standard JCA 1.0
e fornisce un'interfaccia Java programmabile (vedere [IMB_CTG]).
Il CTG contiene un Java Gateway Application che permette di
comunicare con programmi in esecuzione su un server CICS,
fornisce un'interfaccia ECI (External Call Interface) per
chiamate di programmi CICS da applicazioni NON-Cics "COMMAREA-based"(transazioni),
un'interfaccia EPI (External Presentation Interface) per l'utilizzo
di applicazioni CICS come terminali 3270 cioè "terminal
based" (mappe) e un'interfaccia ESI (External Security
Interface).
Figura 9: CICS Transaction Gateway (CTG)
Nel file XML del RA ra.xml vengono indicate inoltre le classi
factory CCI e Managed del connettore che servono per la stipula
dei System Contracts tra l'Application Server ed il RA.
Nel caso del connettore Comporsys la classe Managed Factory
(che implementa javax.resource.spi.ManagedConnectionFactory)
indicata dal tag la classe <managedconnectionfactory-class>
è la classe de.comporsys.connector.cics.ManagedConnectionFactoryImpl
mentre quella CCI (che implementa javax.resource.cci.ConnectionFactory
ed è indicata dal tag <connectionfactory-impl-class>)
è la
de.comporsys.connector.cics.cci.ConnectionFactoryImpl.
Di
fatto la classe del connettore Comporsys che implementa l'interfaccia
SPI ManagedConnection wrappa al suo interno un'oggetto di
classe com.ibm.ctg.client.JavaGateway jgaConnection così
come un oggetto ManagedConnection del MokaConnector wrappava
un oggetto java.io.File mentre quella di sample della SUN
una java.sql.Connection
E
arriviamo a parlare (finalmente) del client del RA: l'EJB
MokaCicsEci.
L'EJB
ha la seguente Remote interface che dichiara un metodo di
business che riceve in ingresso una stringa e restituisce
un long (il valore della lunghezza della stringa text ricevuta
in ingresso):
public
interface MokaCicsEci extends EJBObject {
public long getLength(String text) throws RemoteException;
}
L'EJB
è di fatto il client del RA e si occupa di interagire
con il RA:
public
long getLength(String text) {
Connection connection = null;
Interaction
interaction=null;
try
{
InitialContext
ic = new InitialContext();
Object
obj = ic.lookup("java:comp/env/eis/cics");
ConnectionFactory
cciCf=(ConnectionFactory)obj;
ConnectionSpecImpl
connSpec = new ConnectionSpecImpl("ale", "maio");
connection
= cciCf.getConnection(connSpec);
interaction
= connection.createInteraction() ;
InteractionSpecImpl
spec = new de.comporsys.connector.cics.cci.InteractionSpecImpl();
spec.setFunctionName("MY_PGM_COB");
MOKARECORD
input = new MOKARECORD();
MOKARECORD
output = new MOKARECORD();
input.setWS_STRINGA(text);
interaction.execute(spec,
input, output);
return
output.getWS_COUNTER();
}
catch(
javax.naming.NamingException e ){
}
catch(
javax.resource.ResourceException e ){
}
}
A
livello di deployment descriptor dell'EJB bisogna indicare
il riferimento alla risorsa JCA mediante il tag <resource-ref>
nel file ejb-jar.xml e indicare la risorsa "fisica"
nel file proprietario dell'Application Server (vedere [MOKA_JCA_5]).
Il
client dell'EJB si occupa di invocare il metodo getLength()
dell'EJB verificando che il risultato sia corretto:
public
class MokaCicsEciClient {
public static void main(String[] args) {
try {
Context initial = new InitialContext(properties);
Object objref = initial.lookup("MokaCicsEciEJB");
MokaCicsEciHome home = (MokaCicsEciHome)
PortableRemoteObject.narrow(objref,MokaCicsEciHome.class);
MokaCicsEci eci = home.create();
long res=eci.getLength("ciao");
if(res==4){
System.out.println("SUCCESS
!" + res);
}
else{
System.out.println("Risultato
Atteso DIVERSO da quello ottenuto: " + res);
}
System.out.println("MokaCicsEciClient:
TEST OVER!");
}
catch(Exception e){
...
}
}
Per
provare l'esempio bisogna effettuare il deploy del RAR e del
Jar dell'EJB di prova e mandare in esecuzione il programma
client MokaCicsEciClient.
Il client di test invierà all'EJB, mediante protocollo
RMI, la stringa "ciao". L'EJB demanderà al
RA l'accesso al programma CICS ritornando al client il risultato
4 (la lunghezza della parola "ciao").
Figura 10: Architettura dello scenario proposto
Conclusioni
Rispetto al complesso scenario dell'integrazione (vedere [MOKABOOK2_JCA]),
lo scopo di JCA ad oggi è sostanzialmente limitato
al mondo degli Adapter e copre quindi una parte relativamente
piccola dell'intera piattaforma d'integrazione.
La
specifica Java Connector Architecture (JCA), seppur orientata
al solo ambito J2EE, assume nello scenario dei Resource Adapter
una grande rilevanza in quanto è uno dei primi tentativi
di stabilire uno standard nel campo dell'integrazione di EIS.
L'importanza
di JCA è innegabile. Basta vedere come, ad oggi, sul
mercato molti vendor già supportano le specifiche JCA
rendendo disponibili molti Resource Adapter per differenti
EIS, tra questi SAP, CICS, IMS, Oracle, PeopleSoft,
(per
una lista completa vedere [JCAIS]).
Bibliografia
e riferimenti
[MOKA_INT6] S.Rossini: Integrazione di applicazioni Enterprise
VI parte: il panorama d'insieme,Mokabyte N.83 -Marzo 2004
[MOKA_EAI_IM] S.Rossini-G.Morello: Integrazione di applicazioni
Enterprise (parte VII): l'Integration Middleware Mokabyte
N.88 - Settembre 2004
[MOKABOOK2_JCA] S.Rossini-G.Morello:: "Manuale pratico
di Java: La piattafroma J2EE" (Capitolo 12: JCA), HOPS-2004
[http://www.mokabyte.it/manualejava2/download.htm]
[MOKA_JCA1] S.Rossini-G.Morello:: "JCA: I parte: la teoria",
Mokabyte N.66 - Settembre 2002
[MOKA_JCA2] S.Rossini: "JCA: II parte: CCI la teoria",
Mokabyte N.67 - Ottobre 2002
[MOKA_JCA3] S.Rossini: "JCA: III parte: CCI la pratica",
Mokabyte N.68 - Novembre 2002
[MOKA_JCA4] S.Rossin :"JCA: IV parte: il Resource Adapter
e i System Contracts", Mokabyte N.69 - Dicembre 2002
[MOKA_JCA5] S.Rossini: "JCA: "V parte: il Resource
Adapter MokaConnector", Mokabyte N.70 - Gennaio 2003
[JCA] http://java.sun.com/j2ee/connector/
[JCA_SPEC] J2EE Connector Architecture Specification, http://java.sun.com/j2ee/download.html#connectorspec
[JRCA] 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.
[PROD] JCA Industry Support, http://java.sun.com/j2ee/connector/industry.html
[JTUT] J2EE Tutorial, http://java.sun.com/j2ee/tutorial/download.html:
Dale Green and Beth Stearns: example of black box resource
adapter for J2EE reference implementation (examples/src/connector/cci
dal j2ee-1_3-doc-tutorial-draft5.zip
[COMPORSYS] http://www.comporsys.de
[COMPORSYS_DWLD] http://www.comporsys.de/de/download/
[COMPORSYS_IARG] Connector for IBM CICS/TXSeries Version 1.5:
Installation And Reference Guide
[IBM_CTG] IBM CICS Transaction Gateway V5.1: http://www-306.ibm.com/software/htp/cics/ctg/overview.html
[RB_CTG] IBM RedBook sg246133: CICS Transaction Gateway V5
The WebSphere Connector for CICS
[RB_JCA_CICS] IBM RedBook sg246401: Java Connectors for CICS:
Featuring the J2EE Connector Architecture
[IWAS_J2C] RedBook sg246133: Integrating WebSphere Application
Server and CICS using the
JCA- http://www-306.ibm.com/software/os/zseries/pdf/G224-7218-00_CICS_JCA_WP.pdf
[JCAIS] J2EE Connector Architecture Industry Support: http://java.sun.com/j2ee/connector/industry.html
|