Introduzione

Grazie ai web services, che sono i pilastri portanti dell'architettura SOA, è possibile garantire un livello di integrazione sempre maggiore tra ambienti eterogenei e di conseguenza ampliare la visibilità di procedure scritte precedentemente per architetture tradizionalmente conosciute come "chiuse". Nello specifico creeremo un web service scritto in Java in grado di chiamare un programma AS400/iSeries RPG.

Lo strumento di sviluppo e le risorse necesarie

Come strumento di sviluppo utilizzeremo ASTK (Application Server Toolkit) basato sulla tecnologia Eclipse. ASTK anche se viene considerato fondamentalmente uno strumento di assemblaggio per la pubblicazione e il testing delle applicazioni su WebSphere può essere utilizzato anche per lo sviluppo di applicazioni Java EE. Per l'interazione con la macchina AS400/iSeries ci appoggeremo a librerie messe a disposizione dal Toolbox Java di IBM, ovvero una raccolta di classi Java che consentono di accedere ai dati e alle risorse presenti sui sistemi AS400/iSeries. Nel nostro esempio utilizzeremo la versione Open Source del Toolbox conosciuta con il nome JTOpen che attualmente è arrivata alla versione 6.0.

La logica di business

La logica di business è rappresentata da una procedura RPG (si veda il codice sottostante) che, a fronte di due parametri di input (rispettivamente la data e il codice del fondo di investimento), restituisce il valore unitario di quest'ultimo.

Il punto di partenza

Per la creazione del servizio partiamo dal sorgente wsdl che rappresenta la nostra logica e, al fine di ottenere un maggior livello di astrazione e riutilizzo, i tipi di dati (schema) utlizzati dal servizio, non sono direttamente inseriti all'interno del sorgente wsdl, ma in un file .xsd indipendente.Di seguito sono riportati lo schema e il wsdl utilizzati nell' esempio.

Quota.xsd <?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:ts="http://www.quota.schema.com" targetNamespace="http://www.quota.schema.com"> <complexType name="QuotaRequestType"> <sequence> <element name="fondo" type="string"/> <element name="data" type="string"/> </sequence> </complexType> <complexType name="QuotaResponseType"> <sequence> <element name="valore" type="string"/> </sequence> </complexType> </schema> Quota.wsdl <?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions xmlns:tns="http://www.quota.wsdl.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns="http://www.testquote.iSeries.com" name="QuotaFondo" targetNamespace="http://www.quota.wsdl.com"> <wsdl:types> <schema elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:quota="http://www.quota.schema.com" targetNamespace="http://www.quota.wsdl.com" xmlns:tns="http://www.quota.wsdl.com"> <import schemaLocation="Quota.xsd" namespace="http://www.quota.schema.com"/> <element name="QuotaInput"> <complexType> <sequence> <element name="QuotaInput" type="quota:QuotaRequestType"/> </sequence> </complexType> </element> <element name="QuotaOutput"> <complexType> <sequence> <element name="QuotaOutput" type="quota:QuotaResponseType"/> </sequence> </complexType> </element> </schema> </wsdl:types> <wsdl:message name="QuotaRequestMessage"> <wsdl:part name="parametri" element="tns:QuotaInput"/> </wsdl:message> <wsdl:message name="QuotaResponseMessage"> <wsdl:part name="parametri" element="tns:QuotaOutput"/> </wsdl:message> <wsdl:portType name="QuotaPort"> <wsdl:operation name="getQuota"> <wsdl:input message="tns:QuotaRequestMessage"/> <wsdl:output message="tns:QuotaResponseMessage"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="QuotaBinding" type="tns:QuotaPort"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getQuota"> <soap:operation soapAction=""/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="ValoreQuota"> <wsdl:port name="QuotaPort" binding="tns:QuotaBinding"> <soap:address location="http://localhost:9080/QuotaServicePrj/services/ValoreQuota"/> </wsdl:port> </wsdl:service> </wsdl:definitions>

Il workspace e i progetti

Come prima cosa lanciamo lo strumento ASTK e creiamo il workspace sul quale vogliamo lavorare, per esempio D:\workspace\Quota. Creiamo un progetto semplice che chiameremo SharedLibray (fig. 1) nel quale copieremo tutti gli oggetti JAR di comune utilità, nel nostro caso in particolare tutti i pacchetti presenti nella cartella lib di JTOpen.

Figura 1 - Creazione Progetto SharedLibrary

Creiamo ora il vero e proprio progetto web dinamico che ospita il servizio e il progetto enterprise al quale sarà associato (Fig. 2)

Figura 2 - Creazione del progetto web dinamico e del progetto enterprise

Lasciamo tutti i parametri di default e dopo la creazione andiamo nelle proprietà del progetto web, selezioniamo: percorso di generazione e aggiungiamo al progetto tutti i jar presenti nel progetto SharedLibrary (fig. 3).

Figura 3 - Aggiunta jars al progetto

La creazione del servizio

Il prossimo passo è quello di copiare nella cartella src del progetto QuotaServicePrj gli archivi Quota.wsdl e Quota.xsd. Passiamo ora a generare il servizio vero e proprio partendo dal nostro wsdl.

Figura 4 - Creazione del servizio web

Al termine di questo passo avremo a disposizione la classe wrapper "vuota" (riportata di seguito) alla quale dovremo fornire successivamente l'implementazione.

package com.wsdl.quota.www;
public class QuotaBindingImpl implements com.wsdl.quota.www.QuotaPort{

  public com.wsdl.quota.www.QuotaOutput getQuota(
  com.wsdl.quota.www.QuotaInput parametri) throws java.rmi.RemoteException {

  return null;

  }

}

Quota.pcml <pcml version="4.0"> <program name="QuotaRPG" path ="/QSYS.LIB/MYLIB.LIB/MYPGM.PGM" threadsafe="false"> <data name="fondo" type="char" usage="input" length="10"/> <data name="valuta" type="char" usage="input" length="8"/> <data name="valore" type="char" usage="output" length="10"/> </program> </pcml> Il tag program name rappresenta il nome "logico" del programma mentre path identifica il programma target che nello specifico è ubicato nella libreria MYLIB (nella libreria di sistema QSYS) e ha come nome MYPGM. L'attributo threadsafe viene utilizzato quando l'applicazione Java e la procedura risiedono sullo stesso server; in questo caso entrambi vengono eseguiti nello stesso job e nello stesso thread. Il file Quota.pcml deve essere copiato nella cartella src del progetto QuotaServicePrj in questo modo viene automaticamente inserito nella cartella classes dell'applicazione Web.

package com.wsdl.quota.www;
import com.schema.quota.www.*;

import com.ibm.as400.access.AS400;

import com.ibm.as400.data.ProgramCallDocument;
public class QuotaBindingImpl implements QuotaPort {

	public QuotaOutput getQuota(QuotaInput parametri)
	throws java.rmi.RemoteException {
AS400 conn = new AS400("serverIP", "utente", "password");

		QuotaOutput qout = new QuotaOutput();

		QuotaResponseType qres = new QuotaResponseType();

		try {

			ProgramCallDocument pcml = new ProgramCallDocument(conn, "Quota");

			pcml.setValue("QuotaRPG.fondo", parametri.getQuotaInput()
					.getFondo());

			pcml.setValue("QuotaRPG.valuta", parametri.getQuotaInput()
					.getData());

			boolean pgm = pcml.callProgram("QuotaRPG");

			if (pgm != true) {

				System.out.println("Errore MYLIB/MYPGM");

			}
 else {

				String risultato = (String) pcml.getValue("QuotaRPG.valore");

				qres.setValore(risultato);

				qout.setQuotaOutput(qres);

			}

		}
 catch (Exception ex) {

			System.out.println("Errore MYLIB/MYPGM");

			ex.printStackTrace();

		}
 finally {

			if (conn != null) {

				conn.disconnectService(AS400.COMMAND);

			}

		}

		return qout;

	}

}
Per prima cosa viene creata una connessione (rilasciata poi nel finally) verso la macchina AS400 specificando indirizzo IP, utente e password;
 successivamente viene istanziato un oggetto di tipo ProgramCallDocument specificando nel suo costruttore la connessione appena creata e il nome del sorgente PCML: Quota (.pcml è assunto come default).
L'oggetto ProgramCallDocument coopera con il server DCP (Distribuited Programm Call) per lo scambio dei paramtri richiesti dall'applicazione;
 il metodo setValue imposta i parametri richiesti dalla procedura RPG precedentemente definiti nel sorgente pcml. L'esecuzione vera e propria della procedura RPG avviene grazie al metodo callProgram al quale viene passato il nome del programma specificato nel tag program name. Se l'invocazione ha avuto esito positivo, il valore di ritorno viene ottenuo invocando il metodo getValue. Le classi com.ibm.as400.access.AS400 e com.ibm.as400.data.ProgramCallDocument si trovano nel package jt400.jar.