MokaByte 83 - Marzo 2004 
Integrazione di applicazioni En-terprise
VI parte
di
Stefano Rossini
Assicurare la possibilità di far comunicare tra loro applicazioni eterogenee (cioè sviluppate su framework, piattaforme e/o sistemi operativi diversi) sta diventando ormai un elemento chiave per l'evoluzione dei nuovi sistemi informatici.
Le soluzioni di integrazione riguardano sia l'implementazione di applicazioni o di sistemi informatici creati ex novo, sia la gestione delle tecnologie aziendali preesistenti, in modo da non intaccare gli investimenti precedenti.
Le esigenze possono essere limitate al semplice scambio di dati o evolversi fino alla possibilità di utilizzare metodi offerti da sistemi remoti per integrare servizi di terzi nella propria applicazione.

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

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