Nella
miniserie dedicata all'integrazione di applicazioni
Enterprise (vedere [INT1, INT2, INT3,INT4,INT5]) sono
stati proposti alcuni semplici esempi di integrazione.
Lo scenario proposto era costituito dalle seguenti quattro
applicazioni:
- Applicazione
A: un'applicazione J2EE (Tomcat+JBoss) che offre un
servizio di concatenazione tra due stringhe inserite
dall'utente. Il servizio di business è costituito
da un EJB Session Stateless ConcatBean che espone
un unico metodo di business:
public
String concat(String a, String b) {return a + b;}
- Applicazione
B: un'applicazione J2EE interamente installata su
Weblogic il cui scopo è di calcolare la lunghezza
di una stringa inserita dall'utente. L'EJB Session
Stateless CalculatoreBean mette a disposizione il
seguente metodo di business:
public
int getLength(String a) { return a.length();}
- Applicazione
C: l'analogo dell'applicazione A sviluppata però
su Framework Microsoft .NET ed installata su Internet
Information Server. Il servizio di business è
costituito dall'oggetto remoto .NET MokaServant che
mette a disposizione il seguente metodo di business
:
public
int getLength(String param) { return param.Length;}
- Applicazione
D: è un'applicazione CORBA che utilizza l'ORB
MICO. Il CORBA Servant mette a disposizione il seguente
metodo di business:
CORBA::Short
CalcolatriceImpl::strlen_calc(const char* msg) throw
(CORBA::SystemException)
{ return (strlen(msg)); }
Definite
le applicazioni da integrare si è visto, nel
corso dei vari articoli, come il livello di "profondità"
d'integrazione ha i suoi pro e i suoi contro da un punto
di vista architetturale, implementativo, di risorse
e di tempo.
Gli esempi presentati avvenivano su livelli d'integerazione
di "profondità" diversa; nello specifico
si è visto come integrare l'applicazione A (applicazione
integrante-sistema outbound) con le applicazioni B,
C e D a livello di:
User interface integration (figura 1(1), 1(2))
- Object/RPC
integration: RMI, RMI-IIOP, CORBA, .NET Remote (figura
1(3), 1(4))
- Message
Integration: JMS e Web Services (figura 1(5))
- Data
Integration
Figura 1- Livelli di integrazione/interoperabilità
tra l'applicazione A e le applicazioni B, C e D
(clicca sull'immagine per ingrandire)
L'integrazione
a livello di User Interface è un'integrazione
"lasca" che fa in modo che applicazioni indipendenti
tra loro presentino la medesima interfaccia utente (vedi
[INT2]).
Questo approccio ha il vantaggio di non essere oneroso
sia in termini tecnici che di tempo ed è consigliabile
laddove non si necessiti di distinguere da quale applicazione
provengano i dati. Una prima possibile modalità
d'integrazione a livello d'interfaccia dell'applicazione
A con l'applicazione B e C è possibile mediante
l'utilizzo dei frameset HTML. Questo approccio ha il
vantaggio di essere facile e "veloce"da implementare
permettendo di avere un documento con delle form indipendenti
tra loro che "puntano" ai Server delle applicazioni
d'interesse. Gli svantaggi derivano dalla necessità
di gestire il focus del frame, la sincronizzazione delle
frames, la modalità di passaggio dati da un frame
all'altro, l'apertura di una connnessione per ogni frame,
le differente implementazione in funzione del browser
adottato dal client, ed altro ancora. Di seguito è
riportato un esempio di pagina HTML composta da diversi
frame ognuno dei quali collegato ad un server differente:
<html>
<frameset
rows="*,*,*">
<frame name="primo" src="/app_A/jsp/concat.jsp">
<frame name="secondo" src="http://localhost:7001/app_B_WLS/jsp/wordlength.jsp">
<frame name="terzo" src="http://localhost/app_C_IIS/asp/wordlength.asp">
</frameset>
</html>
Un'altra
possibile modalità d'integrazione prevede lo
sviluppo di un nuovo controller nell'applicazione A
(outbound) che ha il compito di effettuare la corretta
invocazione della risorsa richiesta agendo di fatto
da dispatcher.
Il client comunica con l'applicazione A che, in modo
trasparente, rioccupa di invocare le risorse sia della
propria web application, che delle altre applicazioni
(B e C).
Se il dispatcher deve invocare una risorsa sulla medesima
web application può utilizzare il metodo forward
del RequestDispatcher ottenuto dal ServletContext (l'oggetto
implicito application che fa riferimento alla web application
corrente).
<%
String action=request.getParameter("APPLICAZIONE");
if(action.equals("APPLICATION_A")){
RequestDispatcher rd = application.getRequestDispatcher("/jsp/concat.jsp");
rd.forward(request, response);
}
Se
il dispatcher deve invocare un'applicazione installata
nel medesimo Servlet Container ma in un'altra web application
(come nel caso in cui si decidesse di effettuare il
porting dell'applicazione B da Weblogic a Tomcat) medesima
web application può utilizzare il metodo ServletContext.getContext()
per "puntare" alla WebApp d'interesse, per
poi invocare la risorsa mediante il metodo RequestDispatcher.forward().
else
if(action.equals("APPLICATION_B")){
ServletContext sc = application.getContext("/app_b_WLS
");
RequestDispatcher rd = sc.getRequestDispatcher("/jsp/wordlength.jsp");
rd.forward(request,response);
}
Nel
caso il dispatcher deve invocare un'applicazione (remota)
dovrà utilizzare il metodo Response.sendRedirect()
che redireziona il client ad una nuova URL indicata
nella Response:
else
if(action.equals("APPLICATION_C")){
response.sendRedirect(http://manowar:80/app_c_IIS/asp/wordlength.asp");
}
%>
Per
integrare maggiormente l'applicazione A e l'applicazione
B è possibile pensare di consentire l'invocazione
diretta del servizio di calcolo della lunghezza della
stringa da parte dell'applicazione A, senza dovere essere
quindi obbligati a navigare tra le pagine JSP dell'applicazione
B.
L'integrazione
Object/RPC prevede di affrontare l'integrazione a livello
di oggetti distributi (EJB, CORBA, DCOM, .NET Remote,
), cioè mediante l'invocazione RPC dei
metodi di business degli oggetti remoti (vedi [INT2]).
Per fare questo è possibile invocare da JBoss
(applicazione A) l'EJB Calculator installato sull'application
server Weblogic (applicazione B).
Si è visto come sia possibile invocare con il
protocollo t3 di Weblogic l'EJB Calculator installando
su JBoss l'opportuno jar e referenziando le proprietà
JNDI con i seguenti valori:
java.naming.factory.initial=
weblogic.jndi.WLInitialContextFactory
java.naming.provider.url= t3://<<SERVER>>:7001
Più
comunemente nella realtà può capitare
che il servizio da integrare restituisca un proprio
object model (non semplici stringhe) che quindi occorre
trasformare nei Value Object del dominio integrante.
Inoltre è possibile che una volta ottenuti i
dati si debbano effettuare elaborazioni di business
aggiuntive come operazioni di gestione/trasformazione/mapping/normalizzazione
dei dati
Per gestire questa situazione si è visto come
sia opportuno sviluppare un EJB Facade che di fatto
agisce sia da Facade verso gli EJB che da adapter nei
confronti dei dati.
In questo modo il client del servizio vede un unico
punto d'accesso al business tier (l'EJB Facade installato
su JBoss) e deve conoscere un unico object model (il
ValueObject di classe ResultOM):
Properties
properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
properties.put(Context.PROVIDER_URL, "jnp://localhost:1099");
Context ctx = new InitialContext(properties);
Object ref = ctx.lookup("Mokafacade");
FacadeHome home = (FacadeHome) PortableRemoteObject.narrow(ref,FacadeHome.class);
Facade facade= home.create();
ResultOM res= this.facade.getResult(param1,param2);
Nello
scenario in cui invece si deve fare interoperare l'applicazione
A e D (dove il servizio di calcolo della lunghezza di
una stringa, precedentemente esposto con un EJB ora
è disponibile mediante un Servant CORBA scritto
in C++) si è visto come utilizzare CORBA (vedi
[INT3]).
Partendo
dall'IDL del servizo CORBA:
module
eai{
interface Calcolatrice{
short strlen_calc(in string
msg);
};
};
si
è proceduto alla sua compilazione mediante il
compilatore IDLJ presente nel JDK.
I file Java ottenuti sono stati utilizzati dal client
Java per accedere in modo trasparente all'applicazione
CORBA:
//
create and initialize the ORB
ORB orb = ORB.init(args, null);
// si ricava il root naming context(NameService=persistente
TNameService=transient)
org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
// nome logico dell'oggetto remoto
NameComponent nc[] = { new NameComponent("eai",
""),
new NameComponent("calcolatrice", "")
};
// Lookup + narrow dell'oggetto remoto
Calcolatrice obj= CalcolatriceHelper.narrow(ncRef.resolve(nc));
// invocazione del metodo remoto
System.out.println("Risultato:
" + obj.strlen_calc("Hello!"));
Per
specificare al client dove trovare il Naming Server
e su quale porta TCP è in ascolto è possibile
usare o la modalità proprietaria SUN mediante
le proprietà ORBInitialPort e ORBInitialHost
oppure la modalità standard CORBA specificando
la proprietà ORBInitRef:
%JAVA_HOME%\bin\java
-classpath %CLASSPATH% CalculatorTestClient
-ORBInitRef NameService=corbaloc:iiop:<<SERVER>>:1666/NameService
Le
operazioni di concatenazione e di calcolo della lunghezza
della stringa sono entrambe di natura sincrona essendo
implementate mediante componenti sincroni quali gli
EJB Session Stateless e quindi il client deve aspettare
l'esito dell'operazione di business prima di potere
proseguire la sua elaborazione.
La
Message Integration, prevede lo scambio dei dati sotto
forma di messaggi utilizzando prtocolli come JMS, SOAP,
HTTP,
Al
contrario delle architetture basate su ORB, l'integrazione
Message-oriented permette un forte disaccoppiamento
tra i sistemi integranti e integrati per la natura intrinsecamente
asincrona dei sistemi di messaging.
Con
JMS è possibile disaccoppiare il client dall'operazione
di calcolo della lunghezza della stringa ad esempio
mediante un EJB Message Driven che gestisce in modo
asincrono l'invocazione del servizio della lunghezza
della stringa (vedi [INT4]).
Il client comunica in modo indiretto con il MDB inviando
mediante JMS un messaggio contenente la stringa di cui
si vuole sapere la lunghezza ad una opportuna destinazione
JMS senza essere costretto a rimanere in attesa del
risultato per proseguire la sua elaborazione.
Il MDB provvederà a notificare il chiamante dell'avvenuta
ricezione della richiesta di elaborazione (richiesta
di calcolo della lunghezza della stringa) mediante un
messaggio JMS e a inoltrare il risultato (la lunghezza
della stringa) ad esempio via email.
public
class CalculatorMDB implements MessageDrivenBean, MessageListener
{
public void onMessage(Message message){
ObjectMessage om = (ObjectMessage) message;
MyMessage msg = (MyMessage)om.getObject();
FacadeHome home = (FacadeHome)MyServiceLocator.getHome(Defines.FACADE_SERVICE);
Façade facade= home.create();
ResultOM res= this.facade.getResult(msg.getInputBody());
. . . . .
javax.mail.Message msg = new javax.mail.internet.MimeMessage(session);
msg.setText("" + res);
. . . . .
javax.mail.Transport.send(msg);
Il
MDB agisce da "wrapper" del Sessione Facade
EJB permettendone ne un'invocazione asincrona mediante
JMS.
Come
ultimo esempio si è visto come permettere la
comunicazione tra gli "acerrimi nemici", J2EE
e .NET cioè nel caso specifico come permettere
la comunicazione tra l'applicazione A e l'applicazione
C.
L'accesso
diretto all'oggetto .NET remoto non è possibile
da piattaforme diverse da .NET (es: J2EE, CORBA,
)
a causa dell'incompatibilità di protocollo di
comunicazione.
Bisogna trovare un "fattore comune" di interoperabilità
e la risposta è
Web Services! (vedi [INT5]).
I
Web Services sono applicazioni di rete che sfruttano
SOAP e WSDL per scambiare informazioni espresse in forma
di documenti XML; la loro caratteristica fondamentale
è la capacità di far interoperare applicativi
eterogenei tramite un protocollo text based e firewall
friendly come SOAP.
Il
servizio di business dell'applicazione .NET è
costituito un oggetto remoto .NET MokaServant che mette
a disposizione il metodo di business getLength() che
restituisce la lunghezza del parametro ricevuto in ingresso:
public
class MokaServant : MarshalByRefObject {
public MokaServant(){ }
public int getLength(String param) {
return param.Length;
}
}
L'oggetto
remoto è messo a disposizione da una applicazione
server in ascolto su una porta TCP e provvede a registrare
l'oggetto remoto un nome logico.
Per permettere l'invocazione del servizio da parte dell'Applicazione
Java si deve sviluppare un Web Service .Net che delega
all'oggetto .NET remote la logica di business.
Di fatto il servizio funziona da "wrapper"
dell'oggetto remoto .NET permettendone l'accesso via
SOAP.
Il Web Service preso in esame è una classe C#
che usa il decoratore [WebMethod] per indicare i metodi
da esportare come WebServices:
[WebService(Namespace="urn:Calculator.webservice.dotnet")]
[SoapRpcService()]
public class Calculator:WebService
{
[WebMethod]
public int getLength(string parola)
{
int result = 0;
try{
MokaServant obj =
(MokaServant)Activator.GetObject(
typeof(RemotingSamples.MokaServant),"tcp://localhost:9999/MokaRemotingCalculator");
result=obj.getLength(parola);
return result;
Importante
notare che, per permettere l'interoperabilità
J2EE e .Net, bisogna utilizzare il tag decoratore [SoapRpcService()].
Infatti per default i Web Services .NET prevedono di
utilizzare il document style con parametri literals
mentre il default per Axis è costituito dall'accoppiata
RPC/encoded:
Pertanto, di default, un client Java Axis (l'Applicazione
A) non è in grado di comunicare con un Web Service
.NET.
Per fare comunicare Axis con .NET bisogna forzare uno
dei due tier affinché utilizzi lo stesso tipo
di encoding dell'altro, bypassando di fatto l'impostazione
di default.
Scegliendo di forzare il servizio .NET a esporre il
proprio Web Service in modo che utilizzi RPC style e
Encoded Parameters si deve utilizzare appunto il tag
[SoapRpcMethod()] ottenendo un WS che utilizza la combinazione
RPC/Encoded piuttosto che quella Document / Literal.
Per
invocare il servizio da Java bisogna avvalersi di un
compilatore WSDL-to-Java. Nello specifico si è
usato il tool Axis WSDL2Java di Axis indicando l'endpoint
del Web Service .NET:
java
org.apache.axis.wsdl.WSDL2Java -o ..\src http://localhost/app_c_IIS/ws/Calculator.asmx?wsdl
Questa
operazione permette di ottenere i file Java che agiranno
da Stub del Web Service .NET rendendo trasparente la
comunicazione al client Java.
Compilati i file ottenuti è possibile sviluppare
il client che utilizza le classi precedentemente generate
(CalculatorLocator e CalculatorSoap) con poche righe
di codice:
java.net.URL
endpoint = new java.net.URL(strEndpoint);
CalculatorSoap calc = new CalculatorLocator().getCalculatorSoap(endpoint);
int res=calc.getLength("Ciao!");
System.out.println(res);
Analogamente
a quanto fatto per la comunicazione tra l'Applicazione
A e C, per la comunicazione tra l'Applicazione A e D
è possibile pensare di sviluppare un Web Services
C++ con gSOAP che agisca da "wrapper" per
il Corba servant. In questo modo il servizio di business
dell'applicazione D è accessibile sia mediante
un'invocazione RPC Corba al MokaSevant, sia mediante
un'invocazione SOAP al WS gSOAP.
La
figura 2 riporta i "percorsi" d'integrazione/interoperabilità
riepilogati fino ad ora.
Figura 2: sceneari d'integrazione dove l'Applicazione
A è il sistema outbound
Nel
caso di Integrazione a livello di dati (Data Integration)
i dati sono passati tra i vari sistemi in modo data/record-oriented
e adattati da un formato di un sistema all'altro.
JDBC e JCA ricadono proprio in questa categoria permettondo
l'accesso rispettivamente a DBMS e risorse EIS eterogenee.
Figura 3 - Integrazione a livello dati
Vediamo
adesso cosa comporta il "cambio di ruolo",
cioè l'Applicazione A che diventa da integrante
(outbound) a integrata(inbound).
L'obbiettivo diventa a questo punto permettere alle
Applicazioni B, C e D di invocare il servizio di concatenazione
di due stringhe esposto dall'Applicazione A.
Alcuni scenari saranno duali rispetto al precedente
caso (Applicazione A ingrante), mentre altri casi metteranno
in rilievo nuove problematiche.
Figura 4 - sceneari d'integrazione dove l'Applicazione
A è un sistema inbound
Iniziamo
a considerare il caso in cui il servizio di concatenazione
dell'Applicazione A debba essere utilizzato dall'Applicazione
D.
Il servizio (ConcatBean) è esposto come un EJB
raggiungibile mediante il protocollo JNP di JBoss. Sia
il protocollo JNP (JBOSS) che T3(BEA) sono protocolli
proprietari che "derivano" da RMI e offrono
vantaggi in termini di prestazioni ma non permettono
l'interoperabilità con altri protocolli, come
ad esempio CORBA.
Con questa situazione l'applicazione D non è
in grado di invocare l'Applicazione A.
La
soluzione a questo tipo di integrazione punto-punto
è utilizzare il protocollo RMI-IIOP (vedi [INT3]).
Utilizzando RMI-IIOP, protocollo sviluppato da Sun e
IBM in collaborazione con l'OMG, è possibile
permettere l'interoperabilità tra RMI e CORBA
sfruttando il "collante" offerto dal protocollo
IIOP (Internet Inter-ORB Protocol).
A partire dalla versione 3, JBoss integra l'ORB JacORb
e permette di esportare un EJB mediante IIOP specificando
il valore IIOP dell'attributo <invoker-proxy-binding-name>
nel deployment descriptor dell'EJB.
Un client Java può quindi invocare l'EJB mediante
il protocollo IIOP utilizzando l'ORB SUN specificando
le seguenti proprietà JNDI:
java.naming.factory.initial=
com.sun.jndi.cosnaming.CNCtxFactor
java.naming.provider.url= corbaloc::<<SERVER>>:3528/JBoss/Naming/root
oppure, se si vuole che anche il client Java utilizzi
l'ORB JacORB:
java.naming.factory.initial= com.sun.jndi.cosnaming.CNCtxFactor
java.naming.provider.url= corbaloc::<<SERVER>>:3528/JBoss/Naming/root
-Dorg.omg.CORBA.ORBClass=org.jacorb.orb.ORB
-Dorg.omg.CORBA.ORBSingletonClass=org.jacorb.orb.ORBSingleton
Per
permettere l'invocazione dell'ORB da un client Corba
scritto in un linguaggio diverso da Java (ad es. l'Applicazione
D) bisogna utilizzare il compilatore java-to-idl sui
.class delle interfacce Home e Remote del Calculator
EJB (ad esempio utilizzando l'rmic disponibile con il
JDK con l'opzione -idl).
Bisogna poi compilare i file IDL ottenuti con l'apposito
tool che compila l'IDL nel linguaggio target d'interesse
(es: idl-to-c++, idl-to-java, idl-to-corba,
).
MICO ad esempio fornisce il compilatore idl che trasforma
i file IDL in file C/C++.
I file ottenuti vanno compilati e linkati al programma
client C++ che è quindi in grado di accedere
all'EJB Java mediante protocollo IIOP:
int
main(int argc, char* argv[])
{
CORBA::ORB_var orb;
try {
// Inizializzo l'ORB
orb = CORBA::ORB_init(argc, argv);
// Look up dell'EJB Home specificato dal corbaname URL
CORBA::Object_var home_obj = orb->string_to_object(argv[1]);
// effettuo la narrow
it::mokabyte::eai::my::ejb::ConcatHome_var home =
it::mokabyte::eai::my::ejb::ConcatHome::_narrow(home_obj.in());
// ottengo il remote reference
it::mokabyte::eai::my::ejb::Concat_var conc = home->create();
CORBA::String_var home_ior = orb->object_to_string(conc);
CORBA::WStringValue* msg1 = new CORBA::WStringValue(L"Hello");
CORBA::WStringValue* msg2 = new CORBA::WStringValue(L"
World!");
// invoco il metodo remoto
wcout << L"Risultato = " << conc->getConcat(msg1,msg2)
<< endl;
. . .
Abbandoniamo
ora l'interoperabilità offerta da CORBA e concentriamoci
sull'integrazione attraverso Web Services.
Per permettere l'invocazione del servizio di concatenazione
dell'EJB Concat da parte dell'Applicazione B (.NET)
e D (gSOAP), si deve prevedere di esportare il servizio
mediante un Web Service fatto con Axis che espone il
servizio di business dell'EJB Calculator con una diversa
tecnologia che permette una diversa modalità
di accesso.
Il
framework AXIS permette di esportare direttamente gli
EJB come WS specificando come tipo di provider Axis
"java:EJB".
Nel deployment descriptor del WS bisognerà allora
specificare le interfacce home e remote, il nome e le
property JNDI:
<deployment
xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="MokaConcatService" provider="java:EJB">
<parameter name="className" value="it.mokabyte.eai.my.ejb.ConcatBean"/>
<parameter name="beanJndiName" value="MokaConcat"/>
<parameter name="homeInterfaceName" value="it.mokabyte.eai.my.ejb.ConcatHome"/>
<parameter name="remoteInterfaceName" value="it.mokabyte.eai.my.ejb.Concat"/>
<parameter name="jndiContextClass" value="org.jnp.interfaces.NamingContextFactory"/>
<parameter name="jndiURL" value="localhost:1099"/>
<parameter name="allowedMethods" value="getConcat"/>
</service>
</deployment>
Analogamente
a quanto visto in [INT6] dove, per invocare da Java/Axis
un servizio .NET si è utilizzati il tool WSDL2JAVA,
con Microsoft si ha a disposizione il wsdl.exe per ottenere
una classe stub C# partendo da un WSDL (nell'esempio
proposto il WSDL è quello del servizio Java MokaConcatService
pubblicato con AXIS).
Ottenute
le classi Stub del WS mediante il tool Microsoft wsdl.exe
(nell'esempio proposto è la classe Concat) è
possibile utilizzarle nel client C# del WS:
Concat
ws = new Concat ();
Console.WriteLine("Risultato:" + ws.concat(word1,word2));
Analogo
discorso vale anche per gSOAP dove la generazione delle
classi Stub avviene mediante l'utilizzo del tool wsdlcpp
e soapcpp2. Fra i files che vengono generati ve ne è
uno che contiene la definizione di una classe Proxy
C++ che è possibile utilizzare per invocare il
Web Service con quasi la stessa facilità con
cui potremmo fare una chiamata ad un oggetto locale.
retVal
= myProxy->concat("Hello"," World!",
out);
Conclusioni
In
questo articolo sono state descritte alcune possibili
modalità d'integrazione/interoperabilità
tra Applicazioni Enterprise .
Gli scenari proposti si riferiscono a esigenze puntuali
di comunicazione tra Applicazioni e piattaforme eterogenee
risolte mediante connessioni punto a punto.
La figura 5 riassume gli scenari d'integrazione presi
in considerazione.
Figura 5 - gli scenari d'integrazione analizzati
Bibliografia
[INT1]
S.Rossini: Integrazione di applicazioni Enterprise (I)
MokabyteN.71-Aprile 2003
[INT2] S.Rossini: Integrazione di applicazioni Enterprise
(II) MokabyteN.72-Maggio 2003
[INT3] S.Rossini, A. D'Angeli: Integrazione di applicazioni
Enterprise (III) Mokabyte N.73-Giugno 2003
[INT4] S.Rossini: Integrazione di applicazioni Enterprise
(IV) MokabyteN.74-Luglio/Agosto 2003
[INT5] S.Rossini, A. D'Angeli: Integrazione di applicazioni
Enterprise (V) MokabyteN.74-Settembre 2003
[JW1] Dirk Reinshagen: Connect the enterprise with the
JCA (I),JavaWorld Gennaio 2002
[SOAP_SPEC] "Simple Object Access Protocol - http://www.w3.org/TR/soap
[WSDL] W3C - "Web Services Description Language"
- http://www.w3.org/TR/wsdl
[MOKASHOP_1] G.Puliti: "MokaShop: I parte",
MokaByte 60, Febbraio 2002
[MOKA_FAC] S.Rossini:"SessionFacade",Mokabyte
N.64-Giugno 2002
[MOKA_MVC] S.Rossini:"Model-View-Control",Mokabyte
N.70-Gennaio 2003
[MOKA_MDB] G.Puliti: "EJB 2.0: Message Driven Beans"
Mokabyte N.69-10mbre 2002
[MOKA_JMS] S.Rossini: "JMS-La gestione dei messaggi",
Mokabyte N.60, 61,68,69
[MOKA_MFP] S.Rossini : "Il pattern Message Facade"
Mokabyte N.71 febbraio 2003
[MOKA_AXIS]A. Giovannini: Apache Axis:Il Soap per Java
Mokabyet N.66 7mbre 2002
[MOKA_WS] M. Bigatti: Corso di Java Web Services Mokabyte
N.71 e successivi
[WSDL] W3C - "Web Services Description Language"
- http://www.w3.org/TR/wsdl
[MOKA_RMI-1] G.Puliti: "Remote Method Invocation",Mokabyte
N16 Febbraio 1998
[MOKA_RMI-2] S.Rossini:"Networking in Java Parte
V: RMI",Mokabyte N43, Luglio 2000
[MOKA_GIOP] A.Bemporad: "GIOP/IIOP l'autostradaCorba",Mokabyte
N.25,10mbre 1998
[MOKA_CORBA]L.Bettini:"Java+IDL=CORBA", Mokabyte
N.22, Settembre 1998
[MOKA_IIOP-1] S. Rossini: "RMI-IIOP I,II ",
Mokabyte N.44,45, Settembre/Ottobre 2000
[MOKA_IIOP-3] G. Puliti: "RMI over IIOP",
Mokabyte N.70, Gennaio 2003
[MOKA_ADP] L.Bettini:"Il pattern Adapter",Mokabyte
N.33-Settembre 1999
[TOMCAT] http://jakarta.apache.org/tomcat/index.html
[JBOSS] http://www.jboss.org
[WLS] http://www.beasys.com
[.NET] http://msdn.microsoft.com/library/default.asp?url=/nhp/default.asp?contentid=28000519
[JACORB] http:// www.jacorb.org
[MICO] http://www.mico.org
[AXIS] Apache Group - "Axis", http://xml.apache.org/axis
|