Capire l'ambiente JAX-RPC SI, Parte 1


di Arun Gupta
Feb 2004

traduzione di Alessio Cervellin
Sett 2004

Note sulla traduzione:
per quanto possibile si è cercato di mantenere la struttura sintattica della versione originale, unica variazione è il passaggio dalla forma personale a quella impersonale. Per quanto riguarda i termini tecnici, sono stati tradotti solo nei casi in cui ciò potesse consentire una migliore comprensione del testo e sono ad ogni modo seguiti dal termine originale tra parentesi quadre (es. "WAR file elaborato" [cooked WAR file]). I termini tecnici più noti, ossia quelli che un "addetto del settore" dovrebbe conoscere ampiamente, non sono stati tradotti (sarebbe ridicolo, come si vede in molti libri, tradurre "deployment descriptor" con "descrittore di dispiegamento"!). Infine, per tradurre alcuni termini sono state usate parole non propriamente italiane ma ampiamente diffuse e comprensibili (es. "to deploy=deployare", "to set=settare", ecc.).
Il testo originale è disponibile all'indirizzo http://jax-rpc.dev.java.net/whitepaper/1.1/index-part1.html


Questo white paper spiega come sfruttare al meglio gli strumenti wscompile e wsdeploy che vengono utilizzati per sviluppare, deployare ed invocare un Web Service utilizzando le Java API for XML-based RPC (JAX-RPC). Il presente è il primo di due documenti ed illustra gli strumenti wscompile, wsdeploy e i file di configurazione che utilizzano. Il secondo invece illustra gli scenari più comuni che si possono incontrare nello sviluppo, nel deploy e nell' invocazione di un Web Service e spiega come realizzarli tramite gli strumenti wscompile e wsdeploy.

1.0 Introduzione
2.0 Il wscompile
      2.1 Task Ant
3.0 La configurazione del wscompile
      3.1 A partire dall'interfaccia dell'endpoint del servizio
      3.2 A partire da un WSDL
      3.3 A partire da un Model File
      3.4 A partire da un file di mapping J2EE
      3.5 Funzionalità avanzate
            3.5.1 Aggiungere i Type Mappings
            3.5.2 Aggiungere gli Handlers
            3.5.3 Aggiungere i mapping namespace-to-package
4.0 Il wsdeploy
      4.1 Task Ant
5.0 Il Descrittore di Deployment
6.0 Glossario
7.0 Riferimenti

 

1.0 Introduzione

I Web Service sono applicazioni enterprise che utilizzano standard e protocolli di trasporto aperti basati su XML per scambiare dati con i client che li invocano. La JAX-RPC Standard Implementation (SI) fornisce gli strumenti wscompile e wsdeploy per consentire lo sviluppo, il deploy e l'invocazione di un Web Service. Essa, insieme al wscompile e wsdeploy, è disponibile nel Java Web Services Developer Pack (Java WSDP). Il Java WSDP è un insieme di strumenti gratuiti che possono essere utilizzati per costruire, testare e deployare applicazioni XML, Web Service, e applicazioni Web con le più recenti tecnologie ed implementazioni standard riguardanti i Web Services. Per sviluppare applicazioni di livello enterprise pienamente supportate che utilizzino le tecnologie Web Services, è consigliato l'uso di Sun Java Studio Enterprise e Sun Java System Application Server.
Il ciclo di sviluppo/deploy di un Web Service JAX-RPC richiede entrambi gli strumenti wscompile e wsdeploy. Ciò consiste nell'invocare il wscompile su un'interfaccia Java (conosciuta anche, nelle specifiche JAX-RPC, come interfaccia dell'endpoint di servizio [service endpoint interface]) o su un WSDL per generare gli artefatti [artifatcs] (N.d.T: v. Glossario) menzionati nelle specifiche JAX-RPC (detti anche “artefatti portabili” [portable artifacts]) e un model file. Il model file in JAX-RPC SI è una specifica rappresentazione dell'endpoint di un Web Service o di un client, generato dal wscompile, e generalmente disponibile in un file di tipo .xml.gz. Esso contiene tutte le informazioni sulle strutture dati interne che consente una facile generazione degli artefatti in base all'implementazione. Questi vengono poi assemblati insieme in un file WAR (che chiameremo anche file WAR grezzo [raw WAR]) e un descrittore di deployment. Il wsdeploy prende come input questo file WAR grezzo, lo analizza e genera un WAR file (che chiameremo file WAR elaborato [cooked WAR]) che può essere deployato in un servlet container, esponendo così il Web Service ed il relativo WSDL ai client.
La Figura 1 mostra il ciclo di sviluppo e deploy di un Web Service JAX-RPC SI.

La suddivisione del ciclo di sviluppo e deploy di un Web Service in due appositi strumenti consente anche una separazione logica delle due fasi. Durante la fase di sviluppo il file WAR grezzo conterrà solo gli artefatti portabili, un descrittore di deployment necessario per il successivo deploy, e un model file generato dal wscompile. Il wsdeploy prende questo WAR file grezzo e genera un WAR file elaborato pronto per essere deployato, contenente gli artefatti dipendenti dall'implementazione. Gli scenari più comuni, così come i meccanismi per implementarli, vengono descritti nella sezione 6.0.
Un tipico ciclo di invocazione di un Web Service JAX-RPC utilizza il wscompile. Ciò si traduce nell'invocare il wscompile su un WSDL per generare gli artefatti lato client portabili, come da specifiche JAX-RPC, così come gli artefatti specifici dell'implementazione [implementation-specific artifacts]. Questi vengono utilizzati, assieme al codice client, per invocare il Web Service.
La Figura 2 mostra il ciclo di invocazione di un Web Service JAX-RPC SI.

2.0 Il wscompile

Il wscompile genera diversi artefatti, sia lato client che lato server, richiesti dall'ambiente JAX-RPC per sviluppare, deployare ed invocare un Web Service. E' disponibile sottoforma di script shell e file batch nella cartella JWSDP_HOME/jaxrpc/bin, dove JWSDP_HOME è la cartella dove è stato installato il Java WSDP. Sebbene negli esempi seguenti venga utilizzato lo shell script, entrambi hanno funzionalità identiche.
Lanciando lo script con l'opzione -help verrà visualizzato il seguente output:

Usage: wscompile [options] configuration_file

dove [options] include:

  -classpath <path>         specifica dove trovare le classi di input
  -cp <path>                stesso di -classpath <path>
  -d <directory>            specifica dove salvare i file di output
  -define                   definisce un servizio
  -f:<features>             abilita le funzionalità specificate (vedi sotto)
  -features:<features>      stesso di -f:<features>
  -g                        genera informazioni di debug 
  -gen                      stesso di -gen:client
  -gen:client               genera gli artefatti lato client (stubs, etc.)
  -gen:server               genera gli artefatti lato server (ties, etc.)
  -source <version>         genera codice per la versione JAXRPC SI specificata
                            versioni supportate: 1.0.1, 1.0.3 e 1.1 (predefinita)
  -httpproxy:<host>:<port>  specifica un proxy server HTTP (porta predefinita a 8080)
  -import                   genera solo le interfacce e i value types
  -keep                     conserva i file generati
  -model <file>             scrive il model file nel file specificato
  -nd <directory>           specifica dove mettere i files generati che non siano classi
  -O                        ottimizza il codice generato
  -s <directory>            specifica dove mettere i file sorgenti generati
  -verbose                  mostra i messaggi sull'attività del compilatore
  -version                  stampa informazioni sulla versione
  -mapping <file>           scrive il mapping file JSR 109 nel file specificato

Esattamente una delle opzioni -import, -define, -gen deve essere specificata.

L'opzione -f richiede una lista di funzionalità separate da virgola.

Funzionalità supportate: (-f)

  datahandleronly           mappa sempre gli attachment al tipo DataHandler
  documentliteral           usa la codifica document literal
  rpcliteral                usa la codifica rpc
  explicitcontext           abilita il service context mapping esplicito
  infix:<name>              specifica un prefisso da utilizzare per le classi tie e i serializzatori generati
  infix=<name>              stesso di infix:<name> (no su Windows)
  jaxbenumtype              mappa le enumeration anonime al rispettivo tipo base
  nodatabinding             disabilita il data binding per la codifica literal
  noencodedtypes            disabilita le informazioni sul tipo di encoding
  nomultirefs               disabilita il supporto di riferimenti multipli
  norpcstructures           non genera le strutture RPC (solo per -import)
  novalidation              disabilita la validazione completa dei documenti WSDL importati
  resolveidref              risolve xsd:IDREF
  searchschema              cerca aggressivamente nello schema i sottotipi
  serializeinterfaces       abilita la serializzazione diretta delle interfacce
  strict                    genera codice strettamente aderente alle speciiche JAXRPC 1.1
  useonewayoperations       permette la generazione di operazioni one-way
  wsi                       abilita la WSI-Basic Profile (per document/literal e rpc/literal)
  unwrap                    abilita l' unWrapping di elementi document/literal in modalità wsi
  donotoverride             non rigenera le classi
  donotunwrap               disabilita l' unWrapping di elementi document/literal in modalità wsi (predefinito)

Opzioni ad uso interno (non supportate):
  -Xdebugmodel:<file>       scrive una versione del model su un file
  -Xprintstacktrace         stampa gli stack trace delle eccezioni
  -Xserializable            genera value types che implementano l'interfaccia Serializable

Esempi:
  wscompile -gen -classpath lib/foo.jar;lib/bar.jar -d generated config.xml
  wscompile -gen  -f:infix:Name -d generated config.xml
  wscompile -define -f:nodatabinding -f:novalidation config.xml
  wscompile -import -f:explicitcontext config.xml

Il tool funziona nelle modalità import, define o gen e prende come input un file di configurazione. Il formato del file di configurazione, per ciascuna delle modalità, è definito da uno schema che verrà illustrato nella sezione 4.0.

2.1 Task Ant

Insieme al wscompile viene fornito un task ant. Di seguito sono elencati gli attributi e gli elementi supportati da detto task:

<wscompile
    fork= "
true|false"
    base="
directory for generated class files"
    classpath="
classpath" | cp="classpath"
    define="
true|false"
    gen="
true|false" | client="true|false" | server="true|false"
    import="
true|false"
    features="
wscompile-features"
    HTTPProxy="
proxy host and port"
    model="
model file name"
    mapping="
mapping file name"
    source="
1.0.1"|"1.0.3"|"1.1"(default)
    nonClassDir="
directory for non-class generated files"
    sourceBase="
directory for generated source files"
    optimize="
true|false"
    debug="
true|false"
    keep="
true|false"
    verbose="
true|false"
    version="
true|false"
    xPrintStackTrace="
true|false"
    xSerializable="
true|false"
    xDebugModel="
text model file name"
    config="
tool configuration file name">
</wscompile>

Attribute Description Command line
fork separa il processo wscompile in un'altra JVM n/a
base specifica dove salvare le classi generate -d
classpath specifica dovre trovare le classi di input -classpath
cp stesso di -classpath -cp
define definisce un servizio
-define
gen genera gli artefatti lato client -gen
client genera gli artefatti lato client
-gen:client
server genera gli artefatti lato server
-gen:server
import genera solo le interfacce e i value types -import
features lista di funzionalità separate da virgola -features
f stesso di -features -f
HTTPProxy specifica un proxy HTTP (porta di default 8080) -httpproxy
model scrive il model file nel file specificato
-model
mapping scrive il JSR 109 mapping file nel file specificato
-mapping
source genera codice per la versione specificata di JAX-RPC SI. Versioni supportate: 1.0.1, 1.0.3, and 1.1 (default) -source
nonClassDir specifica dove salvare i file generati che non siano classi -nd
sourceBase specifica dove salvare i file sorgenti generati -s
optimize ottimizza il codice generato
-O
keep conserva i file generati
-keep
debug genera informazioni di debug
-g
verbose stampa messaggi sull'attività del compilatore
-verbose
version stampa informazioni sulla versione
-version
xPrintStackTrace stampa gli stack trace delle eccezioni
-Xprintstacktrace
xSerializable genera value types che implemenano l'interfaccia Serializable
-Xserializable
xDebugModel scive una versione leggibile del model file -Xdebugmodel
config  file di configurazione
configuration file


L'attributo classpath è una struttura di tipo path e può essere settata anche con elementi <classpath> annidati. Prima che questo task possa essere usato, è necessario aggiungere al progetto l'elemento <taskdef> come di seguito:

<taskdef name="wscompile" classname="com.sun.xml.rpc.tools.ant.Wscompile">
    <classpath path="${classpath}"/>
</taskdef>

dove ${classpath} è la lista di classi richieste dall'ambiente JAX-RPC.

Esempi

<wscompile
    gen="true"
    base="${build}"
    features="explicitcontext"
    classpath="xyz.jar"
    debug="true"
    config="config.xml">

L'esempio precedente genera gli artefatti lato client, salva i file .class nella cartella ${build}, e mappa gli header del WSDL ai parametri dei metodi utilizzando il file di configurazione config.xml. Il classpath utilizzato è xyz.jar e la compilazione avviene con le informazioni di debug abilitate.

<wscompile
    import="true"
    keep="true"
    sourceBase="${source.dir}"
    base="${build}"
    model="model.xml.gz"
    xPrintStackTrace="true"
    config="config.xml">
    <classpath refid="compile.classpath"/>
</wscompile>

L'esempio precedente genera le interfacce e i value types per l'endpoint del servizio come da WSDL specificato nel config.xml, salva i file .java nella cartella ${cource.dir}, salva i file .class nela cartella ${build}, e genera il model file model.xml.gz nella cartella corrente. Inoltre stampa lo stack trace nel caso in cui si dovesse verificare una eccezione. Il path è un riferimento ad una struttura di tipo path compile.classpath, definita altrove nell'ambiente di compilazione.

<wscompile
    fork="true"
    define="true"
    nonClassDir="${wsdl.dir}"
    features="documentliteral, useonewayoperations"
    config="config.xml"/>

L'esempio precedente genera un WSDL document/literal nella cartella ${wsdl.dir} per l'interfaccia e l'implementazione dell'endpoint specificato nel config.xml, e mappa i metodi con tipo di ritorno void come operazioni di tipo one-way. Fork =”true” fa sì che venga invocato il compilatore javac predefinito in un processo separato.

 

3.0 La configurazione del wscompile (config.xml)

Il file di configurazione è la fonte primaria di informazioni per il wscompile. Queste informazioni vengono analizzate, insieme ai vari switch specificati durante l'invocazione del wscompile, al fine di generare gli artefatti. Diamo un'occhiata alle dichiarazioni di schema in testa al file di configurazione.

<?xml version="1.0" encoding="UTF-8">
<xsd:schema
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:tns="http://java.sun.com/xml/ns/jax-rpc/ri/config"
       targetNamespace="http://java.sun.com/xml/ns/jax-rpc/ri/config"
    elementFormDefault="qualified"
      attributeFormDefault="unqualified"
      version="1.0">

Lo schema inizia con la dicitura standard XML, poi dichiara lo schema nel namespace definito da targetNamespace, ossia http://java.sun.com/xml/ns/jax-rpc/ri/config. Inoltre definisce altri prefissi di namespace: xsd, che si riferisce al namespace dello schema XML, e tns, che si riferisce al namespace del file di configurazione. Lo schema inoltre richiede che tutti gli elementi dichiarati localmente siano qualificati e gli attributi no.
Il primo elemento è configuration ed è definito come segue:

<xsd:element name="configuration">
    <xsd:complexType>
        <xsd:sequence>
            <xsd:choice>
    
            <xsd:element name="service" type="tns:serviceType"/>
                <xsd:element name="wsdl" type="tns:wsdlType"/>
                <xsd:element name="modelfile" type="tns:modelfileType"/>
                <xsd:element name="j2eeMappingFile" type="tns:j2eeMappingFileType"/>
            </xsd:choice>
        </xsd:sequence>
    </xsd:complexType>
</xsd:element>

Deve contenere uno, e solo uno, degli elementi specificati, corrispondenti alle quattro differenti modalità per fornire informazoni al wscompile. Ciascuno di questi metodi richiede un formato differente per il file di configurazione. Ciascun formato consente di utilizzare il wscompile nelle sue tre funzionalità principali (-import, -define, and -gen). La tabella sottostante mostra come le informazioni vengano fornite al wscompile e il corrispondente formato del file di configurazione. Vengono inoltre messe in relazione le diverse funzionalità del wscompile con ciascun formato.

Nome elemento Come vengono fornite le informazioni al tool ? Modalità consentite dal Wscompile
-import -define -gen
service Una descrizione del servizio basata su un insieme di interfacce dell'endpoint No *
wsdl Un WSDL document da importare ed elaborare
No
modelfile Un model file precedentemente salvato (generato tramite l'opzione -model di wscompile) No No
j2eeMappingFile Mapping J2EE definito secondo la JSR 109 No

* E' raccomandato solo -gen:server perchè gli artefatti lato client dovrebbero essere generati solo a partire dal WSDL esposto dopo che il servizio sia stato deployato.

Di seguito vengono spiegati i vari formati del file di configurazione. Ogni sezione inizia spiegando le schema del file di configurazione e poi viene fornito un esempio di tale formato.

3.1 A partire dall' interfaccia dell' endpoint del servizio

Questo formato viene utilizzato quando la descrizione di un servizio è definita da un set di interfacce, chiamate interfacce dell'endpoint di servizio nelle specifiche JAX-RPC. Di seguito è illustrato lo schema per la definizione degli elementi:

<xsd:complexType name="serviceType">
    <xsd:sequence>
        <xsd:element name="interface" type="tns:interfaceType" minOccurs="0" maxOccurs="unbounded"/>
        <xsd:element name="typeMappingRegistry" type="tns:typeMappingRegistryType" minOccurs="0"/>
        <xsd:element name="handlerChains" type="tns:handlerChainsType" minOccurs="0"/>
        <xsd:element name="namespaceMappingRegistry" type="tns:namespaceMappingRegistryType" minOccurs="0"/>
    </xsd:sequence>
    <xsd:attribute name="name" type="xsd:string" use="required"/>
    <xsd:attribute name="targetNamespace" type="xsd:anyURI" use="required"/>
    <xsd:attribute name="typeNamespace" type="xsd:anyURI" use="required"/>
    <xsd:attribute name="packageName" type="xsd:string" use="required"/>
</xsd:complexType>

L'attributo name viene utilizzato per identificare il servizio. E' obbligatorio e viene utilizzato dal wscompile per:

  • stabilire il nome delle classi interfaccia del servizio generate (come definito nella sezione 4.3.11)

  • generare un attributo name per l'elemento wsdl:definitions nel documento WSDL, se generato

  • dare un nome all'elemento wsdl:service nel documento WSDL, se generato

  • stabilire il nome di altri artefatti generati a runtime

  • risolvere conflitti di nome

L'attributo targetNamespace, ti tipo anyURI, viene utilizzato come namespace di destinazione per il documento WSDL generato. E' un attributo obbligatorio.

L'attributo typeNamespace, di tipo anyURI, viene utilizzato come namespace di destinazione per lo schema XML inserito nella sezione <type> del documento WSDL generato. E' un attributo obbligatorio.

L'attributo packageName, di tipo string, specifica il nome del package java nel quale vengono generati gli artefatti relativi al servizio.

L'elemento interface, di tipo interfaceType (definito sotto), viene utilizzato per specificare la descrizione dell'interfaccia dell'endpoint del servizio. E' un elemento opzionale. Sebbene si stia specificando un servizio a partire dal Java, si avrà avrà sempre almeno un elemento interface nel file di configurazione.

L'elemento typeMappingRegistry, di tipo typeMappingRegistryType (definito nella sezione 3.5.1), viene utilizzato per specificare il type mapping registry utilizzato per tutte le interfacce del servizio specificato. E' un elemento opzionale. Se assente, verrà utilizzato il type mapping registry standard supportato dall'ambiente JAX-RPC. Il type mapping standard supporta il set di tipi di dato XML specificato nella codifica SOAP 1.1 e nelle specifiche XML. Il type mapping standard inoltre specifica il mapping XML per il set di tipi Java supportati da JAX-RPC. Questo elemento è richiesto solo se l'applicazione deve supportare il mapping tra altri tipi di dato XML e altri tipi di dato Java oltre a quelli previsti dal mapping standard.

L'elemento handlerChains, di tipo handlerChainsType (definito nella sezione 3.5.2), viene utilzzato per specificare la catena di handler che verrà eseguita su client e/o sul server per tutte le interfacce definite nel servizio.

L'elemento namespaceMappingRegistry, di tipo namespaceMappingRegistryType (definito nella sezione 3.5.3), viene utilizzato per definire il mapping tra namespace XML e i package Java per tutte le interfacce del servizio.

Da notare che dato che tutti gli elementi vengono definiti in sequenza, essi devono comparire nello stesso ordine specificato nello schema.

Si dia un'occhiata agli altri tipi utilizzati per definire questa sezione prima di analizzare un file di configurazione di esempio. Il seguente è lo schema per l'elemento interfaceType:

<xsd:complexType name="interfaceType">
    <xsd:sequence>
        <xsd:element name="handlerChains" type="tns:handlerChainsType" minOccurs="0"/>
    </xsd:sequence>
    <xsd:attribute name="name" type="xsd:string" use="required"/>
    <xsd:attribute name="servantName" type="xsd:string"/>
    <xsd:attribute name="soapAction" type="xsd:string"/>
    <xsd:attribute name="soapActionBase" type="xsd:string"/>
</xsd:complexType>

Come già detto, questo elemento viene utilizzato quanto la definizione di un endpoint è basata sull'interfaccia dell'endpoint stesso.

L'attributo name, di tipo string, specifica il fully-qualified name dell'interfaccia dell'endpoint del servizio (un' interfaccia Java). E' un attributo obbligatorio.

L'attributo servantName, di tipo string, specifica il fully-qualified name della classe di implementazione dell'endpoint del servizio.

L'attributo soapAction, di tipo string, specifica la stringa SOAPAction da utilizzare per tutte le operazioni dell'interfaccia. E' un attributo opzionale.

L'attributo soapActionBase, di tipo string, specifica l'URI base per la stringa SOAPAction. La SOAPAction per una determinata operazione viene ottenuta appendendo il nome dell'operazione al valore specificato qui. Questo attributo è in mutua esclusione con soapAction. E' un attributo opzionale.

L'elemento handlerChains, di tipo handlerChainsType (definito nella sezione 3.5.2), viene utilizzato per specificare le catene di handler che verranno eseguite sul client e/o sul server per l'interfaccia dell'endpoint del servizio. Gli handler definiti a livello di interfaccia vanno in override agli handler definiti a livello di servizio.

Esempi

Si consideri un Web Service per quotazioni di borsa definito dalla seguente interfaccia dell'endpoint:

package com.example;

public interface StockQuoteProvider extends java.rmi.Remote {
    public float getLastTradePrice(String tickerSymbol)
        throws java.rmi.RemoteException,
               com.example.InvalidTickerException;
    public StockQuoteInfo getStockQuote(String tickerSymbol)
        throws java.rmi.RemoteException,
               com.example.InvalidTickerException;
}

public class InvalidTickerException extends java.lang.Exception {
    protected String tickerSymbol;
    public InvalidTickerException(String tickersymbol) { this.tickersymbol = tickerSymbol }
    public String getTickerSymbol() { return tickerSymbol; }
}

Un file di configurazione di esempio per un servizio così definito è il seguente:

<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
    <service name="
StockQuoteService"
        targetNamespace="
http://stockquote.org/wsdl"
        typeNamespace="
http://stockquote.org/types"
        packageName="
com.example">
            <interface
                name="
com.example.StockQuoteProvider"
                servantName="
com.example.StockQuoteImpl">
            </interface>
    </service>
</configuration>

com.example.StockQuoteProvider è l'interfaccia dell'endpoint e com.example.StockQuoteImpl ne è l'implementazione. Tutti gli artefatti per questa interfaccia vengono generati nel package com.example come specificato nell'attributo packageName.
Supponendo che StockQuoteInfo sia un JavaBeans con i soli metodi di accessor e mutator, l'interfaccia e l'implementazione dell'endpoint utilizzano le classi standard supportate da JAX-RPC. In questo caso non c'è necessità di specificare il typeMappingRegistry. Di seguito vengono illustrati alcuni estratti del relativo WSDL: 

<definitions
    name="
StockQuoteService"
    targetNamespace="
http://stockquote.org/wsdl"
    xmlns:tns="http://stockquote.org/wsdl"
    xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:ns2="http://stockquote.org/types"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">

...

    <types>
        <schema
            targetNamespace="
http://stockquote.org/types"
            xmlns:tns="http://stockquote.org/types"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
            xmlns="http://www.w3.org/2001/XMLSchema">

...

<portType name="StockQuoteProvider">

...

<binding name="
StockQuoteProviderBinding" type="tns:StockQuoteProvider">

...

    <service name="StockQuoteService">
        <port name="
StockQuoteProviderPort" binding="tns:StockQuoteProviderBinding">
            <soap:address location="REPLACE_WITH_ACTUAL_URL"/>
        </port>
    </service>
</definitions>

In grassetto sono evidenziati gli attributi del WSDL che sono stati presi dal file di configurazione. La tabella seguente mostra come gli attributi del WSDL siano derivati dal file di configurazione:

Valore dell'attributo nel WSDL Relazione con gli attributi nel file di configurazione
definitions{name} Copiato da service{name} 
defintions{targetNamespace} Copiato da service{targetNamespace}
schema{targetNamespace} Copiato da service{typeNamespace}
portType{name} Derivato dall' unqualified class name delle interfacce come specificato in interface{name}
binding{name} Derivato dall' unqualified class name delle interfacce come specificato in interface{name} e concatenando "Binding"
service{name} Copiato da service{name} 
port{name} Derivato dall' unqualified class name delle interfacce come specificato in interface{name} e concatenando "Port"

L'indirizzo dell'endpoint per ogni porta presente nel WSDL verrà correttamente valorizzato quando il WSDL sarà deployato.

 

3.2 A partire da un WSDL

Questo formato viene utilizzato quando la descrizione di un servizio si ha sottoforma di un documento WSDL oppure quanto gli artefatti lato client devono essere generati a partire da un WSDL. Di seguito è mostrato lo schema per specificare l'elemento service:

<xsd:complexType name="wsdlType">
    <xsd:sequence>
        <xsd:element name="typeMappingRegistry" type="tns:typeMappingRegistryType" minOccurs="0"/>
        <xsd:element name="handlerChains" type="tns:handlerChainsType" minOccurs="0"/>
        <xsd:element name="namespaceMappingRegistry" type="tns:namespaceMappingRegistryType" minOccurs="0"/>
    </xsd:sequence>
    <xsd:attribute name="location" type="xsd:anyURI" use="required"/>
    <xsd:attribute name="packageName" type="xsd:string" use="required"/>
</xsd:complexType>

L'attributo location, di tipo anyURI, specifica l'URL del documento WSDL. Tale documento può risiedere sia sul file system che da qualunque altra parte su internet. E' un attributo obbligatorio.

L'attributo packageName, di tipo string, specifica il nome del package Java da utilizzare per la generazione degli artefatti. E' un attributo obbligatorio.

L'elemento typeMappingRegistry, di tipo typeMappingRegistryType (definito nella sezione 3.5.1), viene usato per specificare il type mapping registry utilizzato per tutte le porte del servizio.

L'elemento handlerChains, di tipo handlerChainsType (definito nella sezione 3.5.2), viene utilizzato per specificare la catena di handler che verrà eseguita sul client e/o sul server per tutte le porte definite nel servizio.

L'elemento namespaceMappingRegistry, di tipo namespaceMappingRegistryType (definito nella sezione 3.5.3), viene utilizzato per definire il mapping tra namespace e package Java per tutte le porte del servizio.

Se il WSDL risiede su internet, allora potrebbe essere necessaria l'opzione -httpproxy del wscompile nel caso in cui si è dietro un firewall.

Esempi

Di seguito viene illustrato un file di configurazione di esempio per il WSDL generato secondo le modalità appena viste:

<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
    <wsdl location="
./StockQuoteService.wsdl"
        pacakgeName="
com.example"/>
</configuration>

Questo file di configurazione presuppone che il fle StockQuoteService.wsdl sia presente nella directory corrente e il wscompile genererà gli artefatti nel package com.example.

 

3.3 A partire da un Model File (avanzato)

Un model file è una rappresentazione dell'endpoint o del client di un Web Service specifica di JAX-RPC SI, generata dal wscompile, generalmente disponibile come file .xml.gz. Esso contiene tutte le informazioni relativamente alle strutture dati interne che consentono più facilmente la generazione degli artefatti specifici dell'implementazione. Dato che il wsdeploy supporta solo un set limitato di switch, la maggior parte di quelli specificati durante l'esecuzione del wscompile vengono memorizzati come parte del model.
Questo formato viene utilizzato quando è definita la descrizione di un servizio o quando gli artefatti lato client devono essere generati a partire da un file model, attraverso l'opzione -model del wscompile. In questo caso lo schema per specificare l'elemento service in questo caso è il seguente:

<xsd:complexType name="modelfileType">
    <xsd:sequence>
    </xsd:sequence>
    <xsd:attribute name="location" type="xsd:anyURI" use="required"/>
</xsd:complexType>

L'attributo location, di tipo anyURI, specifica l'URL del file model (tipicamente con estensione .xml.gz). Questo file può risiedere sia sul file system locale che da qualunque altra parte su internet. Se il model risiede su internet, allora l'opzione -httprpoxy del wscompile potrebbe rendersi necessaria quando ci si trova dietro un firewall.

Esempi

Un file di configuazione di esempio a partire da un file model è il seguente:

 <configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
    <modelfile location="
./model.xml.gz"/>
</configuration>

Questo file di configurazione presuppone che il file model.xml.gz si trovi nella cartella corrente.

 

3.4 A partire da un file di mapping J2EE (avanzato)

Un file di mapping J2EE contiene informazioni che mettono in corrispondenza il mapping tra le interfacce Java e le definizioni WSDL. Uno strumento di deploy J2EE utilizza queste informazioni assieme al file WSDL per generare gli stub e i tie per i servizi deployati.
Questo formato viene utilizzato quando la descrizione di un servizio è definita in un file di mapping J2EE pre-esistente e viene usato solo in un ambiente J2EE. Lo schema per specificare l'elemento service in questo caso è il seguente:

<xsd:complexType name="j2eeMappingFileType">
    <xsd:attribute name="location" type="xsd:anyURI" use="required"/>
    <xsd:attribute name="wsdlLocation" type="xsd:anyURI" use="required"/>
</xsd:complexType>
L'attributo location, di tipo anyURI, specifica l'URL del file di mapping J2EE.

Un file di mapping J2EE e/o il WSDL possono risiedere sia sul file system locale che in qualunque altra parte su internet. Se uno dei due è su internet, allora l'opzione -httpproxy del wscompile potrebbe essere necessaria se si è dietro un firewall.

Esempi

Un file di configurazione di esempio a partire da un file di mapping J2EE è il seguente:

 <configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
    <j2eeMappingFile location="
./stock-mapping.xml"
        wsdlLocation="
StockQuoteService.wsdl"/>
</configuration>

Questo file di configurazione presuppone che stock-mapping.xml  e StockQuoteService.wsdl si trovino nella directory corrente.

3.5 Funzionalità avanzate

Questa sezione descrive le funzionalità avanzate dello strumento wscompile. Le funzionalità descritte sono utilizzabili solo con i file di configurazione di wscompile a partire dall'interfaccia dell'endpoint o da un WSDL.

3.5.1 Aggiungere i Type Mappings

Nelle fasi di sviluppo, deploy e invocazione di un Web Service è raccomandabile utilizzare il type mapping standard di JAX-RPC. Specificare un mapping personalizzato rende il Web Sevice, e i suoi client, non portabili.
Si prenda in considerazione il caso in cui la classe com.example.StockQuoteInfo, della sezione 3.1, non sia un JavaBeans e dunque non supportata dall'ambiente standard JAX-RPC (ad esempio java.util.Vector utilizzato come una delle variabili membro). E' necessario associare un type mapping con questa interfaccia che faciliti il mapping tra i tipi Java e i tipi XML. Lo schema per specificare questo type mapping è il seguente:

<xsd:complexType name="typeMappingRegistryType">
    <xsd:sequence>
        <xsd:element name="import" type="tns:importType" minOccurs="0"/>
        <xsd:element name="typeMapping" type="tns:typeMappingType" minOccurs="0" maxOccurs="unbounded"/>
        <xsd:element name="additionalTypes" type="tns:additionalTypesType" minOccurs="0"/>
    </xsd:sequence>
</xsd:complexType>

L'elemento import, di tipo importType (definito sotto), è una lista di schemi XML che descrive i tipi definiti dall'utente, di solito sono i tipi utilizzati dai serializzatori pluggable.

L'elemento typeMapping, di tipo typeMappingType (definito sotto), è una sequenza di type mapping. Da notare che questo elemento ha una cardinalità "unbounded", quindi può apparire più volte, una per ciascuna codifica.

L'elemento additionalTypes, di tipo additionalTypesType (definito sotto), è una lista di tipi Java addizionali che devono essere elaborati anche quando non compaiono nelle interfacce del servizio. Questa elaborazione consiste nel generare serializzatori e deserializzatori per ogni classe che sia un JavaBean per poi inserirli nel type mapping registry creato dal tool che viene utilizzato a runtime. Ciò può servire se la classe memorizzata in java.util.Vector non compare in nessuno delle signature dei metodi dell'endpoint. Altrimenti, il tool elabora solo le classi che compaiono nell'endpoint.

Lo schema per importare una lista di schemi è il seguente:

<xsd:complexType name="importType">
    <xsd:sequence>
        <xsd:element name="schema" type="tns:schemaType" minOccurs="0" maxOccurs="unbounded"/>
    </xsd:sequence>
</xsd:complexType>

L'elemento schema, di tipo schemaType (definito sotto), è una lista di schemi da importare.

<xsd:complexType name="schemaType">
    <xsd:sequence>
        <xsd:attribute name="namespace" type="xsd:anyURI" use="required"/>
        <xsd:attribute name="location" type="xsd:anyURI" use="required"/>
    </xsd:sequence>
</xsd:complexType>

L'attributo namespace, di tipo anyURI, specifica il namespace che il documento descrive. E' un attributo obbligatorio.

L'attributo location, di tipo anyURI, specifica un URL che punta allo schema. E' un attributo obbligatorio.

Si consideri il caso in cui lo schema per la classe java.util.Vector sia disponibile nel namespace http://schema.org/java/collections/vector all'indirizzo  http://stockquote.org/types/vector. In questo caso, l'elemento import sarà:

<import>
    <schema
        namespace="
http://schema.org/java/collections/vector"
        location="
http://stockquote.org/types/vector/schema"/>
</import>

Lo schema per definire il type mapping per una particolare codifica è il seguente:

<xsd:complexType name="typeMappingType">
    <xsd:sequence>
        <xsd:element name="entry" type="tns:entryType" minOccurs="0" maxOccurs="unbounded"/>
    </xsd:sequence>
    <xsd:attribute name="encodingStyle" type="xsd:anyURI" use="required"/>
</xsd:complexType>

L'elemento entry, di tipo entryType (definito sotto), definisce una lista di type mapping.

L'elemento encodingStyle, di tipo anyURI, specifica l' URI che indica la codifica. E' un attributo obbligatorio e andrebbe settato a stringa vuota nel caso di literal.

Lo schema che definisce un type mapping per una codifica è il seguente:

<xsd:complexType name="entryType">
    <xsd:sequence>
        <xsd:attribute name="schemaType" type="xsd:QName" use="required"/>
        <xsd:attribute name="javaType" type="xsd:string" use="required"/>
        <xsd:attribute name="serializerFactory" type="xsd:string" use="required"/>
        <xsd:attribute name="deserializerFactory" type="xsd:string" use="required"/>
    </xsd:sequence>
</xsd:complexType>

L'attributo schemaType, di tipo QName, identifica il nome di un tipo di schema. E' un attributo obbligatorio.

L'attributo javaType, di tipo string, identifica il fully qualified name della corrispondente classe java. E' un attributo obbligatorio.

L'attributo serializerFactory, di tipo string,  identifica il fully qualified name della classe serializer factory da utilizzare per questo tipo. E' un attributo obbligatorio.
La serializer factory fornisce un meccanismo per accedere al serializzatore che sarà in grado di serializzare la rappresentazione Java di java.util.Vector in una rappresentazione XML.

L'attributo deserializerFactory, di tipo string, identifica il fully qualified name della classe deserializer factory da utilizzare per questo tipo. E' un attributo obbligatorio.
La deserializer factory fornisce un meccanismo per accedere al deserialzizatore che sarà in grado di deserializzare la rappresentazione XML nella rappresentazione Java di java.util.Vector.

Esempi

Continuando con il solito esempio, si consideri il caso in cui lo schema importato definisca il tipo XML per la classe java.util.Vector con un elemento dal nome "vector". Inoltre, si supponga di avere disponibili le serializer e deserializer factory in com.example.VectorSerializerFactory e com.example.DeserializerFactory. In questo caso l'elemento typeMapping sarà il seguente:

<typeMapping encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <entry
        schemaType="
ns1:vector"
        javaType="
java.util.Vector"
        serializerFactory="
com.example.SerializerFactory"
        deserializerFactory="
com.example.DeserializerFactory"
        xmlns:ns1="
http://schema.org/java/collections/vector"/>
</typeMapping>

Si noti che l'elemento schemaType proviene dal namespace importato. La scrittura di queste serializer e deserializer factory non rientra nell'ambito di questo articolo.
Diciamo che la classe java.util.Vector usata nell'esempio memorizza istanze di una classe JavaBean. Dato che questa classe non compare da nessuna parte nell'interfaccia, il wscompile non sarà in grado di generare i relativi serializzatori e deserializzatori. Specificandola nell'elemento additionalTypes, si dice al wscompile di generare gli artefatti di serializzazione per questa classe.
Questo è uno schema per specificare una lista di tipi Java addizionali da essere elaborati dal wscompile:

<xsd:complexType name="additionalTypesType">
    <xsd:sequence>
        <xsd:element name="class" type="tns:classType" minOccurs="0" maxOccurs="unbounded"/>
    </xsd:sequence>
</xsd:complexType>

L'elemento class, di tipo classType (definito sotto), identifica una lista di classi da essere elaborate.

<xsd:complexType name="classType">
    <xsd:sequence>
        <xsd:attribute name="name" type="xsd:string" use="required"/>
    </xsd:sequence>
</xsd:complexType>

L'elemento name identifica il nome della classe da essere elaborata.

Nel solito esempio, se com.example.StockDailyHighs è memorizzato in un java.util.Vector, l'elemento additionalType sarà:

<additionalTypes>
    <class name="
com.example.StockDailyHighs"/>
</additionalTypes>

Aggregando tutte le informazioni sul type mapping, l'elemento typeMappingRegistry sarà:

<typeMappingRegistry>
    <import>
        <schema
            namespace="
http://schema.org/java/collections/vector"
            location="
http://stockquote.org/types/vector/schema"/>
    </import>
    <typeMapping encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/">
        <entry
            schemaType="
ns1:vector"
            javaType="
java.util.Vector"
            serializerFactory="
com.example.SerializerFactory"
            deserializerFactory="
com.example.DeserializerFactory"
            xmlns:ns1="
http://schema.org/java/collections/vector"/>
    </typeMapping>
    <additionalTypes>
        <class name="
com.example.StockDailyHighs"/>
    </additionalTypes>
</typeMappingRegistry>

Dunque il file di configurazione completo per l'esempio in oggetto, a partire dall'endpoint di un servizio, è il seguente:

<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
    <service name="
StockQuoteService"
        targetNamespace="
http://stockquote.org/wsdl"
        typeNamespace="
http://stockquote.org/types"
        packageName="
com.example">
            <interface
                name="
com.example.StockQuoteProvider"
                servantName="
com.example.StockQuoteImpl">
            </interface>
            <typeMappingRegistry>
                <import>
                    <schema
                        namespace="
http://schema.org/java/collections/vector"
                        location="h
ttp://stockquote.org/types/vector/schema"/>
                </import>
                <typeMapping encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/">
                    <entry
                        schemaType="
ns1:vector"
                        javaType="
java.util.Vector"
                        serializerFactory="
com.example.SerializerFactory"
                        deserializerFactory="
com.example.DeserializerFactory"
                        xmlns:ns1="
http://schema.org/java/collections/vector"/>
                </typeMapping>
                <additionalTypes>
                    <class name="
com.example.StockDailyHighs"/>
                </additionalTypes>
            </typeMappingRegistry>
</xsd:element>

Sebbene questo esempio parta dall'interfaccia dell'endpoint di un servizio, è  utilizzabile anche come file di configurazione nel caso in cui si parta da un WSDL.

 

3.5.2 Aggiungere gli Handler

L'handler di un messaggio SOAP ha accesso al messaggio SOAP che rappresenta la chiamata o la risposta RPC. Questi handler vengono configurati tramite catene di handler [handler chains] di tipo handlerChainsType (definito sotto):

<xsd:complexType name="handlerChainsType">
    <xsd:sequence>
        <xsd:element name="chain" type="tns:chainType" minOccurs="0" maxOccurs="unbounded"/>
    </xsd:sequence>
</xsd:complexType>

Ogni catena di handler rappresenta una lista ordinata di handler ed è definita dal seguente schema:

<xsd:complexType name="chainType">
    <xsd:sequence>
        <xsd:element name="handler" type="tns:handlerType" minOccurs="0" maxOccurs="unbounded"/>
    </xsd:sequence>
    <xsd:attribute name="runAt" type="tns:runAtType" use="required"/>
    <xsd:attribute name="roles" type="tns:roleListType"/>
</xsd:complexType>

L'attributo runAt, di tipo runAtType (definito sotto), specifica se la catena deve essere eseguita lato client o lato server. E' un attributo obbligatorio in quanto l'utente deve specificare se la catena di handler deve essere configurata sul client o sul server.

L'elemento handler, di tipo handlerType (definito sotto), specifica la sequenza di handler che compone la catena.

Una catena di handler è configurata per agire col ruolo [role] di un o più attori [actor] SOAP, specificati utilizzando un URI denominato SOAP actor name.
Il seguente è lo schema per specificare una lista di ruoli SOAP per una catena di handler, ossia una lista di URI


<xsd:simpleType name=
"roleListType">
    <xsd:list itemType="xsd:anyURI"/>
</xsd:simpleType>

Lo schema per la descrizione di un handler è il seguente:

<xsd:complexType name=
"handlerType">
    <xsd:sequence>
        <xsd:element name="property" type="tns:propertyType" minOccurs="0" maxOccurs="unbounded"/>
    </xsd:sequence>
    <xsd:attribute name="className" type="xsd:string" use="required"/>
    <xsd:attribute name="headers" type="tns:headerListType"/>
</xsd:complexType>

L'attributo className, di tipo string, specifica il fully-qualified name della classe handler. E' un attributo obbligatorio.

L'attributo headers, di tipo headerListType (definito sotto), identifica la lista di nomi di header a cui l'handler dovrà accedere. E' un attributo opzionale.
Gli header specificati in questo attributo saranno resi disponibili all'handler tramite il metodo HandlerInfo.getHeaders (illustrato nell'esempio sottostante). Tali header posso comunque essere cablati anche all'interno del codice stesso dell'handler.

L'elemento property, di tipo propertyType (definito sotto), definisce le proprietà di inizializzazione per l'hanlder.

Il seguente è lo schema per definire una lista di nomi di header utilizzati dall'handler, ossia una lista di QName:

<xsd:simpleType name="headerListType">
    <xsd:list itemType="xsd:QName"/>
</xsd:simpleType>

Questo è lo schema per definire una proprietà di inizializzazione di un handler:

<xsd:complexType name="propertyType">
    <xsd:sequence>
    </xsd:sequence>
    <xsd:attribute name="name" type="xsd:string" use="required"/>
    <xsd:attribute name="value" type="xsd:string" use="required"/>
</xsd:complexType>

L'attributo name, di tipo string, definisce il nome della proprietà

L'attributo value, di tipo string, definisce il valore della proprietà.

Questa invece è la lista di valori che può assumere l'attributo runAt, ed indica che l'handler può essere attivato sia sul client che sul server:

<xsd:simpleType name ="runAtType">
    <xsd:restriction base="xsd:string">
        <xsd:enumeration value="client"/>
        <xsd:enumeration value="server"/>
    </xsd:restriction>
</xsd:simpleType>

Esempi

Continuando sempre con lo stesso esempio, si consideri il caso in cui un client invii una richiesta criptata ad un endpoint e l'endpoint decripti la richiesta prima di esaminarla. Questa funzionalità può essere facilmente implementata inserendo degli  handler lato client e lato server.
Si supponga che com.example.StockEncryptHandler sia configurato come handler lato client e com.example.StockDecryptHandler come handler lato server.
L'elemento handlerChains lato client sarà:

<handlerChains>
    <chain runAt="
client">
        <handler className="
com.example.StockEncryptHandler">
            <property name="
bit" value="128"/>
        </handler>
    </chain>
</handlerChains>

L'elemento handlerChains lato server sarà:

<handlerChains>
    <chain runAt="
server">
        <handler className="
com.example.StockDecryptHandler">
            <property name="
bit" value="128"/>
        </handler>
    </chain>
</handlerChains>

Questo invece è l'elemento handlerChains lato server con specificato un header, che l'handler può ricevere, chiamato session-id nel namespace http://echo.org/example :

<handlerChains>
    <chain runAt="
server">
        <handler
            className="
com.example.StockDecryptHandler">
            xmlns:ns0="http://echo.org/example"
            headers="ns0:session-id"/>
        </handler>
    </chain>
</handlerChains>

Gli header specificati tramite la precedente configurazione possono essere acceduti dall'handler tramite il seguente codice:

public class StockDecryptHandler extends GenericHandler {
    private HandlerInfo config;

    public void init(HandlerInfo config) {
        this.config = config;
    }

    public javax.xml.namespace.QName getHeaders() {
        config.getHeaders();
    }
}

Sebbene questo esempio sia a partire dalle interfacce dell'endpoint del servizio, lo stesso schema è utilizzabile nel caso in cui si parta da un WSDL. Stesso schema viene utilizzato per aggiungere gli handlers al descrittore di  deployment.
Sia gli handler lato client che quelli lato server possono essere configurati tramite questo file di configurazione. Quelli lato client possono essere configurati anche programmaticamente. Ecco un estratto di codice di un handler lato client che registra gli handler in quest'ultima maniera:

package com.example;

...

import javax.xml.rpc.Stub;
import java.util.List;
import java.util.Hashtable;
import javax.xml.rpc.handler.HandlerInfo;
import javax.xml.rpc.handler.HandlerChain;
import javax.xml.rpc.handler.HandlerRegistry;
...

// get the port from generated service
StockQuoteService_Impl serviceImpl = new StockQuoteService_Impl();
StockQuoteServicePort stockPort = serviceImpl.getPort(StockQuoteProvider);

// get the handler registry from generated service (always returns a valid registry)
HandlerRegistry handlerRegistry = serviceImpl.getHandlerRegistry();

// get handler chain from the registry (always returns a valid chain)
List handlerChain = handlerRegistry.getHandlerChain(stockPort);

// create a new HandlerInfo to populate handler data
HandlerInfo handlerInfo = new HandlerInfo();

// set the handler class
handlerInfo.setHandlerClass(StockEncryptHandler);

// populate the properties
Hashtable hashtable = new Hashtable();
hashtable.put("bit", "128");

// set the properties in handler 
handlerInfo.setHandlerConfig(hashtable);

// add the handler to handler chain
handlerChain.add(handlerInfo);

Si faccia riferimento al tutorial del Java Web Services Developer Pack per un esempio su come realizzare un handler.

 

3.5.3 Aggiungere i mapping namespace-to-package

Il mapping del namespace permette di specificare il mapping tra i namespace XML verso/da i package Java. Lo schema per specificare questo mapping è il seguente:

<xsd:complexType name=
"namespaceMappingRegistryType">
    <xsd:sequence>
        <xsd:element name="namespaceMapping" type="tns:namespaceMappingType" minOccurs="0" maxOccurs="unbounded"/>
    </xsd:sequence>
</xsd:complexType>

L'elemento namespaceMapping, di tipo namespaceMappingType (definito sotto), identifica una lista di mapping.
Ciascun mapping di namespace XML da/verso i package Java è definito dal seguente schema:

<xsd:complexType name="namespaceMappingType">
    <xsd:sequence>
    </xsd:sequence>
    <xsd:attribute name="namespace" type="xsd:anyURI" use="required"/>
    <xsd:attribute name="packageName" type="xsd:string" use="required"/>
</xsd:complexType>

L'attributo namespace, di tipo string, identifica il nome del namespace. E' un attributo obbligatorio.

L'attributo packageName, di tipo string, identifica il nome del package. E' un attributo obbligatorio.

Esempi

Si consideri un WSDL avente la seguente sezione <types> :

<types>
    <schema targetNamespace="
http://stockquote.org/types1"
        xmlns="
http://www.w3.org/2001/XMLSchema">
        <complexType name="
tickerSymbol">
            <sequence>
                <element name="
name" type="string"/>
            </sequence>
        </complexType>
    </schema>
    <schema targetNamespace="
http://stockquote.org/types2"
        xmlns="
http://www.w3.org/2001/XMLSchema">
        <complexType name="
tickerSymbol">
            <sequence>
                <element name="
name" type="string"/>
                <element name="
company" type="string"/>
            </sequence>
        </complexType>
    </schema>
</types>

In questo pezzo di WSDL tickerSymbol è un tipo complesso definito in due namespace differenti. Il tickerSymbol definito nel namespace http://stockquote.org/types1 namespace ha solo il simbolo ticker. Il tickerSymbol definito nel namespace http://stockquote.org/types2 contiene anche il nome della compagnia a cui appartiene questo ticker. Affinchè il wscompile generi i corrispondenti value types per entrambi i tipi complessi, è necessario specificare i mapping namespace-to-package nel file di configurazione:

<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
    <wsdl location="
./StockQuoteService.wsdl"
        pacakgeName="
com.example">
        <namespaceMappingRegistry>
            <namespaceMapping namespace="
http://stockquote.org/types1" packageName="com.example.types1"/>
            <namespaceMapping namespace="
http://stockquote.org/types2" packageName="com.example.types2"/>
        </namespaceMappingRegistry>
    </wsdl>
</configuration>

Il wscompile genererà com.example.types1.TickerSymbol e com.example.types2.TickerSymbol con le appropriate variabili membro.

Partendo dall'interfaccia dell'endpoint del servizio, il file di configurazione è il seguente:

<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
    <service name="
StockQuoteService"
        targetNamespace="
http://stockquote.org/wsdl"
        typeNamespace="
http://stockquote.org/types"
        packageName="
com.example">
            <interface
                name="
com.example.StockQuoteProvider"
                servantName="
com.example.StockQuoteImpl">
            </interface>
        <namespaceMappingRegistry>
            <namespaceMapping namespace="
http://stockquote.org/types1" packageName="com.example.types1"/>
            <namespaceMapping namespace="
http://stockquote.org/types2" packageName="com.example.types2"/>
        </namespaceMappingRegistry>
</configuration>

Si supponga che i value type com.example.types1.TickerSymbol e com.example.types2.TickerSymbol siano utilizzati dall'interfaccia dell'endpoint insieme ad altri value type. In questo caso, il WSDL generato avrà una sezione <types> con tre elementi <schema> :

<types>
    <schema targetNamespace="
http://stockquote.org/types"
        xmlns="
http://www.w3.org/2001/XMLSchema">

    . . . <!-- other declarations -->

    </schema>
    <schema targetNamespace="
http://stockquote.org/types1"
        xmlns="
http://www.w3.org/2001/XMLSchema">
        <complexType name="
tickerSymbol">
            <sequence>
                <element name="
name" type="string"/>
            </sequence>
        </complexType>
    </schema>
    <schema targetNamespace="
http://stockquote.org/types2"
        xmlns="
http://www.w3.org/2001/XMLSchema">
        <complexType name="
tickerSymbol">
            <sequence>
                <element name="
name" type="string"/>
                <element name="
company" type="string"/>
            </sequence>
        </complexType>
    </schema>
</types>

Tutti i tipi del package com.example.types1 vengono mappati nel namesapce http://stockquote.org/types1, tutti quelli del package com.example.types2 package in http://stockquote.org/types2, e tutti gli altri tipi nel namespace http://stockquote.org/types.

4.0 Il wsdeploy

Il wsdeploy viene utilizzato congiuntamente al wscompile per generare un file WAR che può essere deployato in qualsiasi servlet container (Tomcat nel caso del Java Web Services Developer Pack). Questo strumento prende in ingresso un file WAR grezzo [raw WAR] contenente l'interfaccia dell'endpoint del servizio, l'implementazione, eventuali value types, eventuali eccezioni specifiche del servizio, un model file, un descrittore di deployment (jaxrpc-ri.xml), e opzionalmente qualsiasi altro artefatto specifico dell'implementazione. Il wsdeploy analizza questo WAR e ne genera un altro specifico dell'implementazione chiamato WAR elaborato [cooked WAR]. Questo processo coinvolge la generazione di serialzizatori, ties, descrittori di runtime, e tutti gli eventuali artefatti necessari per un corretto deploy del Web Service.
Il wsdeploy è disponibile sottoforma di script shell e file batch nella cartella JWSDP_HOME/jaxrpc/bin, dove JWSDP_HOME è la directory di installazione del Java WSDP. Sebbene negli esempi seguenti venga utilizzato lo shell script, entrambi hanno funzionalità identiche.

Lanciando lo script senza alcuna opzione verrà visualizzato il seguente output:

error: missing input WAR file
Usage: wsdeploy <options> <WAR file>

dove <options> include:
  -classpath <path>         specifica un classpath opzionale
  -keep                     mantiene i file temporanei
  -o <output WAR file>      specifica dove salvare il file WAR generato
  -tmpdir <directory>       specifica la directory temporanea da usare
  -verbose                  mostra messaggi sull'attività del compilatore
  -version                  stampa informazioni sulla versione
  -source <version>         genera codice per la versione JAXRPC SI specificata.
                            Le versioni supportate sono: 1.0.1, 1.0.3 and 1.1 (predefinita)

 L'opzione -o è obbligatoria.

Esempi:

  wsdeploy -o target.war myapp.war

Il tool prende il WAR file grezzo myapp.war e genera il file WAR elaborato target.war. 

4.1 Task Ant

Insieme al wsdeploy viene fornito anche un task Ant. Elementi ed attributi supportati da questo task sono: 

<wsdeploy
    fork= "
true|false"
    classpath="
classpath" | cp="classpath"
    outWarFile="
output WAR file name"
    keep="
true|false"
    tmpDir="
temporary directory name"
    verbose="
true|false"
    version="
true|false"
    source="
1.0.1"|"1.0.3"|"1.1"(default)
    inWarFile="
input WAR file name">
</wsdeploy>


Attributo Descrizione Linea di comando
fork separa il processo wsdeploy in un' altra JVM n/a
classpath specifica dove trovare le classi di input
-classpath
keep mantiene i file generati -keep
outWarFile nome del file WAR elaborato [cooked WAR] di output
-o
inWarFile nome del file WAR grezzo [raw War] di input
<WAR file>
tmpDir directory temporanea da usare
-tmpdir
source genera codice per la versione JAXRPC SI specificata. Versioni supportate: 1.0.1, 1.0.3 e 1.1 (default) -source
verbose stampa messaggi sull' attività del compilatore
-verbose
version stampa informazioni sulla versione
-version

L'attributo classpath è una struttura di tipo path e può essere settata anche con elementi <classpath> annidati. Prima che questo task possa essere usato, è necessario aggiungere al progetto l'elemento <taskdef> come di seguito:

<taskdef name="wsdeploy" classname="com.sun.xml.rpc.tools.ant.Wsdeploy">
    <classpath path="${classpath}"/>
</taskdef>

dove ${classpath} è la lista di classi richieste dall'ambiente JAX-RPC.

Esempi

<wsdeploy
    classpath="xyz.jar"
    tmpdir="${tmp}"
    outWarFile="stock.war"
    inWarFile="stock-raw.war"/>

Questo esempio prende il WAR file grezzo stock-raw.war e genera il file WAR elaborato stock.war. Il classpath include xyz.jar, e la directory temporanea è ${tmp}.

<wsdeploy
    keep="true"
    outWarFile="stock.war"
    inWarFile="stock-raw.war">
    <classpath refid="compile.classpath"/>
</wsdeploy>

Questo esempio prende il WAR file grezzo stock-raw.war e genera il file WAR elaborato stock.war. Il classpath è un riferimento alla struttura di tipo path compile.classpath, definita da qualche altra parte nell'ambiente di compilazione, e il file WAR elaborato contiene il codice sorgente degli artefatti lato server generati.

<wsdeploy
    fork="true"
    source="1.0.3"
    outWarFile="stock.war"
    inWarFile="stock-raw.war">
</wsdeploy>

Questo esempio prende il WAR file grezzo stock-raw.war e genera il file WAR elaborato stock.war compatibile con la versione 1.0.3 di JAX-RPC. Fork =”true” fa sì che venga invocato il compilatore javac predefinito in un processo separato.

 

5.0 Il Descrittore di Deployment (jaxrpc-ri.xml)

Il descrittore di deployment, jaxrpc-ri.xml, è incluso nel file WAR grezzo e viene utilizzato dal wsdeploy per generare il file WAR elaborato. Questo descrittore fornisce informazioni necessarie al wsdeploy per deployare il Web Service nel web container. Questa è la dichiarazione in testa a tale descrittore:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
    targetNamespace="
http://java.sun.com/xml/ns/jax-rpc/ri/dd"
    xmlns:xsd="
http://www.w3.org/2001/XMLSchema"
    xmlns:tns="
http://java.sun.com/xml/ns/jax-rpc/ri/dd"
    elementFormDefault="
qualified"
    attributeFormDefault="
unqualified"
    version="1.0">

Lo schema inizia con la dicitura standard XML, poi dichiara lo schema nel namespace definito da targetNamespace, ossia http://java.sun.com/xml/ns/jax-rpc/ri/config. Inoltre definisce altri prefissi di namespace: xsd, che si riferisce al namespace dello schema XML, e tns, che si riferisce al namespace del file di configurazione. Lo schema inoltre richiede che tutti gli elementi dichiarati localmente siano qualificati e gli attributi no.
Il primo elemento è webServices, definito come:


<xsd:element name="
webServices">
    <xsd:complexType>
        <xsd:sequence>
            <xsd:element name="
endpoint" type="tns:endpointType" minOccurs="0" maxOccurs="unbounded"/>
            <xsd:element name="
endpointMapping" type="tns:endpointMappingType" minOccurs="0" maxOccurs="unbounded"/>
        </xsd:sequence>
        <xsd:attribute name="
version" type="xsd:string" use="required"/>
        <xsd:attribute name="
targetNamespaceBase" type="xsd:string"/>
        <xsd:attribute name="
typeNamespaceBase" type="xsd:string"/>
        <xsd:attribute name="
urlPatternBase" type="xsd:string"/>
    </xsd:complexType>
</xsd:element>

L'attributo version, di tipo string, identifica il numero di versione, ed è attualmente riservato per future funzionalità. E' un attributo obbligatorio e il suo valore è fissato a "1.0".

L'attributo targetNamespaceBase, di tipo string, identifica l' URI base per i  target namespace dei WSDL generati per gli endpoint che non hanno un proprio model file.

L'attributo typeNamespaceBase, di tipo string, è simile all'attributo targetNamespaceBase attribute ma viene utilizzato per gli schemi XML inseriti nei WSDL generati.

L'attributo urlPatternBase, di tipo string, identifica il pattern dell' URL base per tutti gli endpoint. Se ne può fare l'override utilizzando l' endpointMapping (vedi sotto).

Per tutte le proprietà base (targetNamespaceBase, typeNamespaceBase, e urlPatternBase) il valore utilizzato per uno specifico endpoint viene espresso aggiungendo al valore base il nome dell'endpoint.

L'elemento endpoint, di tipo endpointType (definito sotto) definisce una sequenza di descrizioni di endpoint.

L'elemento endpointMapping, di tipo endpointMappingType, definisce una sequenza di mapping di endpoint.

Ciascun endpoint all'interno di un elemento webServices è definito dal seguente schema:


<xsd:complexType name="
endpointType">
    <xsd:sequence>
        <xsd:element name="
handlerChains" type="tns:handlerChainsType" minOccurs="0"/>
    </xsd:sequence>
    <xsd:attribute name="
name" type="xsd:string" use="required"/>
    <xsd:attribute name="
displayName" type="xsd:string"/>
    <xsd:attribute name="
description" type="xsd:string"/>
    <xsd:attribute name="
interface" type="xsd:string"/>
    <xsd:attribute name="
implementation" type="xsd:string"/>
    <xsd:attribute name="
port" type="xsd:QName"/>
    <xsd:attribute name="
model" type="xsd:anyURI"/>
    <xsd:attribute name="
wsdl" type="xsd:string"/>
</xsd:complexType>

L'attributo name, di tipo string, definisce il nome dell'endpoint. E' un attributo obbligatorio.

L'attributo displayName, di tipo string, definisce un nome in forma human-readable per l' endpoint.

L'attributo description, di tipo string, definisce una descrizione dell' endpoint.

L'attributo interface, di tipo string, identifica il nome dell'interfaccia dell'endpoint del servizio.

L'attributo implementation, di tipo string, identifica il nome della classe di implementazione del servizio.

L'attributo model, di tipo string, indica il model file, se presente, che descrive l' endpoint.

L'elemento handlerChains, di tipo handlerChainsType (definito sopra), identifica le catene di handler da utilizzare per l'endpoint. Si faccia riferimento alla sezione 4.6 per le informazioni riguardanti l'aggiunta di handler chain nel descrittore di deployment. L'unica differenza sta nel fatto che nel descrittore di deployment si possono specificare solo handler lato server. Le catene di handler possono essere specificate sia nel file di configurazione nel momento in cui si usa il wscompile sia qui nel descrittore di deployment. E' raccomandato comunque specificarle nel file di configurazione. Se le catene di handler vengono specificate nel descrittore di deployment, allora vanno in override delle eventuali catene definite nel file di configurazione del wscompile.

Il descrittore di deployment contiene inoltre i mapping degli endpoint (tipo i mapping delle servlet ch si hanno nel web.xml) ad un URL. Lo schema per definire questi mapping è il seguente:


<xsd:complexType name="
endpointMappingType">
    <xsd:sequence>
    </xsd:sequence>
    <xsd:attribute name="
endpointName" type="xsd:string" use="required"/>
    <xsd:attribute name="
urlPattern" type="xsd:string" use="required"/>
</xsd:complexType>

L'attributo endpointName, di tipo string, identifica il nome dell' endpoint. E' un attributo obbligatorio.

L'attributo urlPattern, di tipo string, definisce l'URL perl'endpoint. E' un attributo obbligatorio.

Si faccia riferimento alla seconda parte di questo white paper per esempi di descrittori di deployment che definiscono degli endpoint.

 

6.0 Glossario

Ant
Ant è uno strumento di build basato su Java sviluppato da Apache. Viene fornito insieme al Java WSDP.
Artifact [artefatto]
è una classe java, un file WSDL, un file model, o qualsiasi altro file generato in automatico dal wscompile o wsdeploy.
cooked WAR [WAR elaborato]
E' un file WAR, generato dal wsdeploy, che può essere deployato in un servlet Web Service di tipo JAX-RPC.
implementation-specific [specifico dell'implementazione]
Specifico di una implementazione JAX-RPC e non raccomandato dalle specifiche. Questa caratteristica lega l'applicazione sviluppata ad una specifica implementazione di JAX-RPC e quindi potrebbe renderla non portabile, ossia si hanno artefatti non portabili [non-portable artifacts]
Java Web Services Developer Pack
Il Java Web Services Developer Pack (Java WSDP) è un set di strumenti che può essere utilizzato per creare, testare e deployare applicazioni XML, Web Service, e applicazioni Web con le più recenti tecnologie ed implementazioni degli standard dei Web Service.
JSR 109
E' una Java Specification Request della Java Community Process (JCP) che definisce il modello di programmazione e l'architettura per implementare un Web Sevice in Java. Per maggiori dettagli si faccia riferimento a http://jcp.org/en/jsr/detail?id=109
Mapping file
contiene informazioni che mettono in relazione i mapping tra le interfacce Java e le definizioni nel WSDL. Uno strumento di deploy J2EE usa queste informazioni insieme al file WSDL per generare gli stub e i tie per il Web Service deployato. Per maggiori dettagli si faccia riferimento a  http://jcp.org/en/jsr/detail?id=109
Model
Il model è una rappresentazione specifica di JAX-RPC SI dell'endpoint o del client di un Web Service, generato dal wscompile, generalmente disponibile sottoforma di file .xml.gz. Contiene tutte le informazioni in quanto alle strutture dati interne che consentono più facilmente la generazione degli artefatti specifci dell'implementazione. Dato che il wsdeploy supporta solo un set limitato di switch, la maggior parte di quelli specificati col wscompile vengono memorizzati come parte del model.
Non-portable artifacts [artefatti non portabili]
Sono gli artefatti con un mapping non definito nelle specifiche JAX-RPC sicchè se vengono generati da multiple implementazioni di JAX-RPC, potrebbero risultare diversi e sono stub, tie e serializzatori.  Sono anche detti artefatti dipendenti dalla specifica [implementation-specific artifacts].
Portable artifacts [artefatti portabili]
Sono artefatti con un ben definito mapping nella specifica JAX-RPC sicchè se vengono generati da multiple implementazioni di JAX-RPC, risulteranno uguali e sono gli endpoint del servizio, le interfacce dell'endpoint, i value types, e le classi di eccezione.
raw WAR [WAR grezzo]
Un file WAR contenente un descrittore di deployment e gli artefatti portabili/non portabili generati dal wscompile. Serve da input per il wsdeploy.
Type mapping registry
Un registry di TypeMappings per diversi stili di codifica.
TypeMapping
E' la rappresentazione di un type mapping per uno o più stili di codifica. Per i tipi di codifica che supporta, un TypeMapping contiene un insieme di tuple di tipo {Java type, SerializerFactory, DeserializerFactory, XML type}. Le SerializerFactory e DeserializerFactory consentono la serializzazione e deserializzazione tra tipi Java e tipi XML. La specifica JAX-RPC definisce un mapping standard tra i tipi XML e i tipi Java che supporta l'insieme di tipi XML definiti nelle specifiche SOAP 1.1 e XML Schema. Il type mapping standard specifica inoltre il mapping per l'insieme di tipi Java supportati da JAX-RPC.
wscompile
Strumento fornito dal JAX-RPC SI incluso nel Java Web Services Developer Pack per la generazione di alcuni artefatti richiesti dalla specifica JAX-RPC e altri artefatti specifici dell'implementazione necessari per sviluppare/deployare/invocare un Web Service.
wsdeploy
Strumento fornito dal JAX-RPC SI incluso nel Java Web Services Developer Pack per ottenere un WAR elaborato [cooked WAR] a partire da un WAR grezzo [raw WAR].


7.0 Riferimenti

  1. Understanding your JAX-RPC SI Environment, Part 2

  2. Java APIs for XML-based RPC

  3. Java Web Services Developer Pack

  4. Sun Java Studio Enterprise

  5. Sun Java System Application Server

  6. Java WSDP Tutorial

  7. Building Web Services with JAX-RPC

  8. JAX-RPC Tools 

  9. SOAP Message Handlers Example

  10. Ant Tool


Note sull'autore

Arun Gupta è un Ingegnere del team di sviluppo delle API per l' XML-based RPC (JAX-RPC) presso la Sun Microsystems. Ha maturato oltre sette anni di esperienza nell'industria del software, lavorando su svariate tecnologie inerenti calcolo distribuito, Java, C++, Web. Attualmente fa parte del team di sviluppo JAX-RPC e rappresenta la Sun all'interno del WS-I Sample Application Working Group. Ha fatto parte del gruppo JAX-RPC sin dalle sue origini ed ha apportato un contributo significativo all'evoluzione della tecnologia.
Il team di sviluppo di JAX-RPC della Sun Microsystems ha fornito un inestimabile contributo a questo white paper.

Per commenti scrivere a: users@jax-rpc.dev.java.net.


Note sul traduttore

Alessio Cervellin è nato nel 1977. E' Ingegnere diplomato presso l' Università di Roma "La Sapienza" in Informatica ed Automatica, e dal 2000 lavora come professionista nel settore dell' Information Technology, specializzandosi sulla piattaforma Java e le tecnologie Web.
Per contatti: a.cervellin@acm.org