Introduzione
Questa
estate, dopo un certo periodo di incubazione, è
stata rilasciata la versione 1.4 beta 2 di J2EE. Diverse
le novità, da JSP 2.0 ad EJB 2.1 - con il Timer
Service, da J2EE Connector architecture che diventa
bidirezionale a migliorie nelle servlet. Ma la grossa
novità è l'integrazione della piattaforma
J2EE con i Web Services, grazie al JSR 109, che consente
di definire i requisiti di deploy per EJB che vogliono
essere esposti come Web Service. Perchè si è
parlato di "incubazione"? Il motivo è
semplice: SUN ha atteso che venisse finalizzato il lavoro
di WS-I (Web Service Interoperability Organization)
sul Basic Profile 1.0, una specifica che vuole aumentare
il grado di interoperabilità dei servizi Web.
Da quello che aziende del calibro di Microsoft ed IBM
hanno "venduto" agli sviluppatori verrebbe
voglia di dare la questione del corretto funzionamento
tra diverse implementazioni degli standard come assodata,
ma la realtà come al solito è diversa.
Due organizzazioni, la prima formale - WS-I, la seconda
informale - SOAP Builders si occupano infatti di verificare
che effettivamente le implementazioni dei vari produttori
funzionino bene tra di loro. Da qui la scelta di SUN
- attendere che le specifiche fossero finalizzate prima
di rilasciare la versione definitiva; sicuramente una
scelta rara nel mondo del software che sembra sempre
rincorrersi a ritmi sempre più vorticosi. Ma
d'altra parte non stiamo parlando di un software 1.0,
ma di una robusta piattaforma, leader per le applicazioni
commerciali d'impresa.
JAX-RPC e JAXR
La parte da leone per il supporto ai servizi Web in
J2EE la fanno le due API JAX-RPC e JAXR, già
note agli early-adopters dei servizi Web nella
piattaforma Java o che comunque hanno deciso di implementare
Web Services al di fuori del contesto J2EE ma in sintonia
con gli standard della piattaforma. Come si ricorderà
[1], JAX-RPC consente di supportare le tecnologie SOAP
e WSDL, definendo una mappatura a due vie tra il mondo
XML e Java. Con JAX-RPC è possibile generare
gli stub e gli skeleton, in modo molto
similare ad RMI, necessari sia alla fruizione di un
servizio che alla sua implementazione. Inoltre JAX-RPC
implementa una interfaccia dinamica (Dynamic Invocation
Interface) che consente di invocare un servizio che
non sia noto a priori - e che quindi non possiede stub
generati in fase di sviluppo.
JAXR [2] supporta invece la tecnologia UDDI, ma le API
sono decisamente più generiche: oltre ad implementare
l'accesso a questo repository di servizi Web, l'interfaccia
di SUN consente anche di accedere ai registri ebXML.
Con JAXR è possibile accedere ai registri globali
per eseguire ricerche incrociate, per classificazione
e per introdurre ed eliminare servizi ed informazioni
dai registri.
Il nuovo acronimo coniato da SUN per lo stack di tecnlogie
implementate da JAX-RPC e JAXR è WUST, che stà
per WSDL, UDDI, SOAP (si, mi chiedo anch'io per cosa
sta la 'T').
Ad ogni modo, la buona notizia è dunque quella
che gli sviluppatori non devono apprendere un nuovo
insieme di API e strumenti, ma possono utilizzare quelli
a loro noti (ed affrontati nei numeri precedenti di
questa rubrica).
Arriva J2EE
La novità più importante nella versione
1.4 di J2EE è dunque l'integrazione di queste
API tramite la JSR 109 ("Web Services for J2EE");
ad RMI e CORBA si aggiunge quindi un nuovo modo per
implementare la programmazione distribuita, ed in particolare
realizzando una via preferenziale per l'integrazione
con .NET. In questo modo, i server J2EE possono essere
acceduti anche da client non J2EE.
L'integrazione di JAX-RPC e JAXR avviene in J2EE in
due momenti differenti. La prima consente che un componente
J2EE, sia esso un EJB oppure una servlet, possa comunicare
in SOAP e descriversi in WSDL; la seconda permette l'accesso
ai registri di servizi Web, in modo da poter ricercare
nei registri mondiali i servizi di proprio interesse,
oltre che a pubblicare e rimuovere i propri.
Inoltre, la specifica JSR 151, che definisce i requisiti
per J2EE 1.4, include anche requisiti per l'interoperabilità,
presi appunto da WS-I. Questa specifica, tra l'altro,
proprio all'interno del Basic Profile 1.0, richiede
come obbligatorio il supporto ad UDDI 2.0; J2EE, in
accordo a questa, implementa il supporto a JAXR sia
sul lato server, in EJB e Servlet, che sul lato client.
Figura 1 - Una visione d'insieme
In figura 1 è mostrata una visione d'insieme
delle tecnologie J2EE, unite alle nuove tecnologie per
i servizi Web. Dalla destra si può notare il
livello dei dati, composto da basi dati, applicazioni
e sistemi legacy; poi si trova il livello EJB, il cuore
della logica applicativa che tramite RMI/JMS dialoga
con il livello Web che oltre alla gestione della consueta
presentazione, si occupa da oggi anche della comunicazione
con l'esterno tramite SOAP.
Percorso di implementazione
La documentazione di SUN suggerisce un workflow operativo
per l'implementazione dei servizi Web in J2EE composto
da sei passaggi.
Questi sono:
- definizione
del servizio Web;
- implementazione
del servizio;
- produzione
del pacchetto di installazione;
- installazione
del pacchetto in un server J2EE;
- pubblicazione
opzionale del servizio e delle informazioni di collegamento
in un registro di Web Services;
- risposta
delle richieste da parte dei client.
I primi passaggi ricordano e ripercorrono sostanzialmente
le operazioni necessarie per realizzare servizi con
JAX-RPC, anche se J2EE introduce alcuni concetti nuovi.
La definizione del servizio, come in JAX-RPC, passa
dalla creazione di un WSDL del servizio, sia direttamente,
che generandolo a partire da una interfaccia Java. Anche
nel caso si parta da un WSDL esistente, sarà
poi necessario generare questa interfaccia. In entrambi
i casi, dunque, si avrà una interfaccia Java
del servizio ed il relativo file WSDL, che andrà
a far parte del pacchetto di installazione. Un esempio
di interfaccia è presente nel listato 1.
Listato 1 - HelloIF.java
package
helloservice;
import java.rmi.RemoteException;
import java.rmi.Remote;
public interface HelloIF extends Remote {
public String sayHello(String name) throws
RemoteException;
}
Come si nota, l'interfaccia estende java.rmi.Remote.
Questo è un requisito delle specifiche, insieme
al fatto che i metodi sollevino una java.rmi.RemoteException,
oltre ad eventuali eccezioni applicative.
Implementazione del servizio
Arrivati alla fase di implementazione, come accennato,
è necessario decidere con quale tipologia di
componente J2EE si intende implementare il servizio.
La piattaforma consente infatti di utilizzare una normale
classe Java, che verrà poi esposta tramite una
Servlet - e dunque ospitata all'interno del Web Container,
oppure di utilizzare un normale EJB di tipo stateless
session - contenuta all'interno dell'EJB Container.
In entrambi i casi sussisono però dei limiti
dell'uso che si può fare del linguaggio, insieme
a quelli già imposti nel caso di EJB. Nello specifico:
- EJB.
Il componente deve essere un EJB session stateless
che implementa tutti i metodi definiti nell'interfaccia,
anche se pare non sia indispensabile implementare
l'interfaccia con implements). Per questi metodi
non è possibile specificare l'attributo di
transazione Mandatory; non è consentito
salvare alcun dato persistente da una chiamata all'altra;
- classe
Java. La classe deve essere pubblica non statica e
non final. Deve dichiarare un costruttore pubblico
senza argomenti per la sua creazione, mentre gli altri
metodi non possono essere final. Come nel caso
di EJB, devono essere implementati tutti i metodi
dell'interfaccia del servizio e non devono essere
salvati dati persistenti da una chiamata all'altra.
Opzionalmente è possibile implementare l'interfaccia
javax.xml.rpc.server.ServiceLifeCycle.
Un esempio di EJB che implementa l'interfaccia vista
nel listato 1 è presente nel listato 2.
Listato
1 - HelloServiceBean.java
package helloservice;
import java.rmi.RemoteException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public class HelloServiceBean implements SessionBean
{
public String sayHello(String name) {
return "Hello " +
name + "from HelloServiceEJB";
}
public
HelloServiceBean() {}
public
void ejbCreate() {}
public
void ejbRemove() {}
public
void ejbActivate() {}
public
void ejbPassivate() {}
public
void setSessionContext(SessionContext sc) {}
}
Come si nota, sono presenti tutti i metodi richiesti
dalla specifica EJB, anche se in realtà questi
sono vuoti.
Figura 2 - Modello di programmazione server
Ciascun metodo del componente Java od EJB ha lo scopo
di implementare quella che nella terminologia dei Web
Services è definita port. L'interfaccia
esposta da una porta è denominata SEI (Service
Endpoint Interface), ottenuta mappando gli elementi
portType di un documento WSDL nel la sua rappresentazione
Java, in accordo alle specifiche JAX-RPC. Ciascun SEI
è dotato di un SIB (Service Implementation Bean)
che implementa appunto i metodi definiti dall'interfaccia.
I nuovi concetti introdotti (SEI e SIB) hanno lo scopo
di disaccoppiare il componente dal modo in cui esiste
nel mondo Java, rispetto a come viene percepito dai
client di servizi Web nel mondo XML (Figura 2).
Produzione del pacchetto
Per costruire l'EAR che conterrà il servizio
Web è necessario compilare alcuni file aggiuntivi,
definiti dalle nuove specifiche per eseguire il collegamento,
oltre che introdurre alcuni elementi aggiuntivi nei
descrittori già esistenti. Nel JAR del componente,
deve essere presente, nella directory META-INF, il nuovo
file webservices.xml (Listato 3) che contiene
la corrispondenza tra l'interfaccia ed il componente
che la implementa, oltre ad altre informazioni di supporto
come il display-name del componente, il riferimento
al WSDL del servizio o il file di mapping per JAX-RPC
(Listato 4). In particolare, le componenti principali
del file webservices.xml sono:
- component-name.
Il nome della porta che non è indispensabile
sia equivalente a quella definita nel WSDL;
- service-impl-bean.
Indica la classe che implementa i metodi del Web Service
- è la classe del componente SIB;
- service-endpoint-interface.
Il nome completo dell'interfaccia (SEI);
- wsdl-port.
Il QName del WSDL che indica il port del WSDL;
- jaxrpc-mapping-file.
Puntamento al file che indica la mappatura tra il
file WSDL alle interfacce JAX-RPC.
Questi file sono prodotti in automatico dagli strumenti
di deploy del server utilizzato utilizzando le informazioni
di configurazione fornite dallo sviluppatore.
Listato
3 - webservices.xml
<?xml version="1.0" encoding="UTF-8"?>
<webservices version="1.1" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/j2ee_web_services_1_1.xsd">
<webservice-description>
<display-name>MyHelloService</display-name>
<webservice-description-name>MyHelloService</webservice-description-name>
<wsdl-file>META-INF/wsdl/MyHelloService.wsdl</wsdl-file>
<jaxrpc-mapping-file>mapping.xml</jaxrpc-mapping-file>
<port-component>
<display-name>HelloIF</display-name>
<port-component-name>HelloIF</port-component-name>
<wsdl-port xmlns:wsdl-port_ns__="urn:Foo">wsdl-port_ns__:HelloIFPort</wsdl-port>
<service-endpoint-interface>
helloservice.HelloIF
</service-endpoint-interface>
<service-impl-bean>
<ejb-link>HelloServiceEJB</ejb-link>
</service-impl-bean>
</port-component>
</webservice-description>
</webservices>
Listato
4 - mapping.xml
<?xml version="1.0" encoding="UTF-8"?>
<java-wsdl-mapping xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://www.ibm.com/webservices/xsd/j2ee_jaxrpc_mapping_1_1.xsd"
version="1.1">
<package-mapping>
<package-type>helloservice</package-type>
<namespaceURI>urn:Foo</namespaceURI>
</package-mapping>
<service-interface-mapping>
<service-interface>helloservice.MyHelloService</service-interface>
<wsdl-service-name xmlns:serviceNS="urn:Foo">serviceNS:MyHelloService</wsdl-service-name>
<port-mapping>
<port-name>HelloIFPort</port-name>
<java-port-name>HelloIFPort</java-port-name>
</port-mapping>
</service-interface-mapping>
<service-endpoint-interface-mapping>
<service-endpoint-interface>helloservice.HelloIF</service-endpoint-interface>
<wsdl-port-type xmlns:portTypeNS="urn:Foo">portTypeNS:HelloIF</wsdl-port-type>
<wsdl-binding xmlns:bindingNS="urn:Foo">bindingNS:HelloIFBinding</wsdl-binding>
<service-endpoint-method-mapping>
<java-method-name>sayHello</java-method-name>
<wsdl-operation>sayHello</wsdl-operation>
<method-param-parts-mapping>
<param-position>0</param-position>
<param-type>java.lang.String</param-type>
<wsdl-message-mapping>
<wsdl-message xmlns:wsdlMsgNS="urn:Foo">wsdlMsgNS:HelloIF_sayHello</wsdl-message>
<wsdl-message-part-name>String_1</wsdl-message-part-name>
<parameter-mode>IN</parameter-mode>
</wsdl-message-mapping>
</method-param-parts-mapping>
<wsdl-return-value-mapping>
<method-return-value>java.lang.String</method-return-value>
<wsdl-message xmlns:wsdlMsgNS="urn:Foo">wsdlMsgNS:HelloIF_sayHelloResponse</wsdl-message>
<wsdl-message-part-name>result</wsdl-message-part-name>
</wsdl-return-value-mapping>
</service-endpoint-method-mapping>
</service-endpoint-interface-mapping>
</java-wsdl-mapping>
Conclusioni
Nel prossimo numero procederemo all'installazione ed
alla pubblicazione del servizio, completando il ciclo
di sviluppo della componente server, che poi potrà
essere utilizzata dai client. Come si vedrà è
necessario utilizzare un piccolo trucco per poter utilizzare
l'SDK di SUN - configurare Windows con impostazioni
internazionali statunitensi - pena l'impossibilità
di creare l'applicazione ed eseguirne il deploy.
Nota:
dove è finito JAXM?
JAXM, la API per la messaggistica SOAP, non è
parte di J2EE 1.4, ma è supportata all'interno
della specifica EJB 2.1, nei message driven bean (MDB).
Nell'ultima versione, infatti, questi componenti possono
ricevere messaggi JAXM oltre che JMS. Inoltre, Connector
1.5 supporta l'utilizzo di diversi tipi di fornitori
di messaggi, JMS provider e JAXM provider).
Bibliografia
e riferimenti
[1] M. Bigatti -"Corso di Java Web Services,
V parte: JAX-RPC", Mokabyte, giugno 2003, http://www.mokabyte.it/2003/06/jws-5.htm
[2] M. Bigatti -"Corso di Java Web Services,
V Iparte: JAXR", Mokabyte, luglio 2003, http://www.mokabyte.it/2003/07/jws-6.htm
[3] Vari - "J2EE 1.4 Tutorial" - http://java.sun.com/j2ee/1.4/docs/tutorial/doc/
|