SOAP Web Services

Note dalla lettura di Beginning Java EE 6 Platform with GlassFish 3 di Antonio Goncalves. Capitolo 14: SOAP Web Services.

SOA (Service-Oriented Architecture) é una architettura che può essere implementata usando servizi web.

I servizi web sono detti debolmente accopiati (loosely coupled) perché il cliente non ha bisogno di conoscere i suoi dettagli implementativi. Il cliente, normalmente chiamato consumer, e il servizio scambiano dati usando documenti XML.

I servizi web forniscono un modo standard per connettere diversi prodotti standard.

In pratica, i web service sono un modo di mettere a disposizione la logica business per mezzo di una interfaccia al consumer. Differentemente da oggetti o EJB, i servizi web usano XML per implementare un accoppiamento debole. L'interfaccia a cui il messaggio viene mandato definisce il formato del messaggio in input e output, e il meccaniscmo per pubblicare e scoprire le interfacce al servizio web.

Il meccanismo opzionale di registrazione dei servizi web (UDDI) permette al cunsumer di trovare il servizio. Una volta trovato lo può contattare via HTTP mandandogli un messaggio XML.

I principali protocolli e tecnologie utilizzati dai servizi web sono:
  • UDDI: Universal Description Discovery and Integration. Una sorta di pagine gialle usate per categorizzare e memorizzare le interfacce ai servizi web.
  • WSDL: Web Services Description Language. Definisce l'interfaccia al servizio web, i tipi di messaggi e dati, interazioni e protocolli.
  • SOAP: Simple Object Access Protocol. Un protocollo basato su XML che definisce la busta (envelope) utilizzata per le comunicazioni del servizio web.
  • HTTP: Hypertext Transfer Protocol. É il protocollo di trasporto normalmente utilizzato per scambiare messaggi, ma é possibile usarne altri come SMTP, FTP o JMS.
  • XML: Extensible Markup Language: É il fondamento su cui sono costruiti i servizi web.
Il registry UDDI punta ad un file WSDL pubblicamente disponibile su internet che il potenziale consumer può scaricare. Si può pensare a WSDL come ad una sorta di interfaccia Java scritta in XML. SOAP definisce il modo in cui i messaggi sono spediti da un computer ad un altro.

STL - Categorie di iteratori

Dal secondo capitolo di Designing Components with the C++ STL, di Ulrich Breymann, dedicato agli iteratori.

La STL fornisce cinque categorie di iteratori:
  • iteratore di input
  • iteratore di output
  • iteratore di avanzamento (forward)
  • iteratore bidirezionale
  • iteratore ad accesso casuale
Iteratore di input

Ha lo scopo di permettere la lettura da uno stream di input sequenziale, ovvero da un istream. Non c'é accesso in scrittura all'oggetto, dunque il dereferenziamento dell'iteratore non fornisce un lvalue.

Ecco un esempio d'uso:

// sourceIterator is an input iterator
sourceIterator = stream_container.begin();
while(sourceIterator != stream_container.end()) {
value = *sourceIterator;
// further calculations with value ...
++sourceIterator;
}

Iteratore di output

Ha lo scopo di scrivere in un container e anche in uno stream di output sequenziale (ostream). Non é possibile accedere in lettura all'oggetto, la dereferenziazione dell'iteratore ha l'unico scopo di permettere l'assegnamento di un valore, in questo modo:

// destinationIterator is an output iterator
*destinationIterator = value;
++destinationIterator; // advance

Di solito le due istruzioni sono combinate:

*destinationIterator++ = value;

Nel caso si usi l'iteratore su uno stream, l'avanzamento é implicito nell'assegnamento. L'operatore ++ in questo caso non fa nulla, ed é presente solo per uniformità sintattica.

Iteratore di avanzamento

Viene utilizzato, ad esempio, per lavorare su una lista singly-linked.

Iteratore bidirezionale

Estende il concetto di iteratore di avanzamento, aggiungendo la capacità di muoversi all'indietro (--). Questo lo rende adatto per la gestione di una lista doubly-linked.

Iteratore ad accesso casuale

Estende il concetto di iteratore bidirezionale, a cui aggiunge l'accesso diretto per mezzo dell'operatore []. Questo permette una gestione analoga a quella dei puntatori in C:

// position is an iterator which points to a location somewhere inside table
n1 = position - table.begin();
cout << table[n1] << endl; // is equivalent to:
cout << *position << endl;
if(n1 < n2)
cout << table[n1] << "lies before " << table[n2] << endl;

STL - Stati di un iteratore

Dal secondo capitolo di Designing Components with the C++ STL, di Ulrich Breymann.

L'iteratore é una generalizzazione del concetto di puntatore. Il suo scopo é di permettere di lavorare in modo omogeneo con diversi container.

Un iteratore può assumere diversi stati.

Se un iteratore viene generato senza essere associato ad un container, finché non viene associato non é dereferenziato. Lo si può comparare a un puntatore a NULL.

Tipicamente un iteratore, quando viene associato ad un container, punta all'inizio del container. Il metodo begin() del container ne fornisce la posizione iniziale. Se il container non é vuoto, l'iteratore può essere dereferenziato. Con l'eccezione della posizione end(), l'iteratore può essere dereferenziato per tutte i valori che possono essere raggiunti in seguito al suo incremento (++).

Il metodo end() di un container é sempre definito e indica la posizione successiva al suo ultimo elemento. Evidentemente non é possibile dereferenziare un iteratore che punti alla posizione dopo la fine del container.

STL - Iteratori

Il secondo capitolo di Designing Components with the C++ STL, di Ulrich Breymann, tratta degli iteratori.

Gli iteratori sono usati dagli algoritmi per muoversi nei container. Si tratta quindi di una estensione del concetto di puntatore per un array.

Le proprietà essenziali per un iteratore sono:
  • l'avanzamento (++);
  • la dereferenziazione (*);
  • il confronto (!= o ==).

Un semplice iteratore seguirà uno schema similie al seguente:

template<class T>
class Iterator {
public:
// constructors, destructor
// ...

bool operator==(const Iterator<T>&) const;
bool operator!=(const Iterator<T>&) const;
Iterator<T>& operator++(); // prefix
Iterator<T> operator++(int); // postfix
T& operator*() const;
T* operator->() const;
private:
// association with the container ...
};


L'operatore -> permette di usare l'iteratore allo stesso modo di un puntatore.
Se il container associato al nostro iteratore fosse un vettore, sarebbe naturale aspettarsi che venga implementato anche operator--().

STL - Concetti Fondamentali

Inizio a leggere Designing Components with the C++ STL, di Ulrich Breymann, che mi sembra un buon libro per rivedersi la STL. A seguire alcune note relative.

I più importanti elementi della STL sono contenitori, iteratori e algoritmi.

I contenitori rendono disponibili iteratori, che sono usati dagli algoritmi.

Nel paragrafo 1.3.4 Breymann ci mostra un piccolo esempio che mostra questa interazione.

Nel libro si inizia da una piccola applicazione che non usa la STL e si modifica a poco a poco il codice per renderlo più generico e adattabile al cambiamento.

Il senso del codice é quello di confrontare l'input fornito dall'utente con un array contenente i primi cento numeri pari, ovvero da 0 a 198. Se il numero passato é nell'array si comunica all'utente a che indice é stato trovato. Per terminare l'esecuzione si immette un non-numero.

Il container utilizzato é un vector, i cui iteratori sono passati all'algoritmo find.

Il codice risultante, applicando anche l'ultimo passo che nel testo é lasciato al lettore, e con qualche piccolo cambiamento aggiuntivo dovuto ai gusti personali, é il seguente:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
const int COUNT = 100;
vector<int> aVector(COUNT);

// fill container with even numbers
for (int i = 0; i < COUNT; ++i)
aVector[i] = 2 * i;

while (true) {
string buffer;
cout << "Enter required number: ";
cin >> buffer;

if(isdigit(buffer[0])) {
int number = atoi(buffer.c_str());

vector<int>::iterator position = find(aVector.begin(), aVector.end(), number);
if (position != aVector.end())
cout << "found: " << (position - aVector.begin()) << endl;
else
cout << number << " not found!" << endl;
}
else
return 0;
}
}

JMS con Glassfish

Note dalla lettura di Beginning Java EE 6 Platform with GlassFish 3 di Antonio Goncalves. Capitolo 13: Sending Messages.

Con l'acronimo JMS, che sta per Java Message Service, intendiamo parlare delle specifiche Java per l'implementazione di un MOM (Message-oriented middleware).

MOM é un provider (detto anche broker) che permette uno scambio asincrono di messaggi tra sistemi eterogenei.

OpenMQ é l'implementazione di riferimento per JMS.

Chi manda un messaggio é detto producer, lo manda a una destinazione (destination) e chi riceve il messaggio é un consumer.

Ci sono due modelli architetturali per JMS, che implicano una differente destinazione.
  • Modello point-to-point (P2P): Il producer mette il messaggio in una coda (queue) che il consumer legge. Quando il consumer conferma la lettura (to acknowledge) il provider rimuove il messaggio dalla coda.
  • Modello publish-subscribe (pub-sub): Il producer pubblica il messaggio su di un topic, e tutti i sottoscrittori lo ricevono.
Le interfacce Java usate variano a seconda del modello utilizzato. Nell'elenco qui sotto in prima posizione é l'interfaccia generica, seguita da quella propria del modello point-to-point e quindi dal pub-sub.
  • Destination, Queue, Topic
  • ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory
  • Connection, QueueConnection, TopicConnection
  • Session, QueueSession, TopicSession
  • MessageConsumer, QueueReceiver, TopicSubscriber
  • MessageProducer, QueueSender, TopicPublisher

Un'occhiata a Glassfish

Note dalla lettura di Beginning Java EE 6 Platform with GlassFish 3 di Antonio Goncalves.

Un'occhiata a Glassfish.

Per default, la porta admin é 4848, la HTTP 8080.

Per far partire il server il comando é: asadmin start-domain domain1

Per accedere la console dell'amministratore (se vale il default) si va sulla pagina http://localhost:4848

L'utente standard é admin - adminadmin

Per terminare la sessione: asadmin stop-domain

Nota che se c'é un solo dominio non é necessario specificarlo.

Terminologia per template

Nel settimo capitolo di C++ Templates: The Complete Guide si parla della terminologia di base sui template.

Si é creata una certa confusione nella terminologia tecnica in questo campo. Ad esempio, ci spiegano gli autori, il termine template class viene utilizzato sia come sinonimo di class template, sia per riferirsi alle classi generate da template, sia per riferirsi a classi con un nome che é un template-id. Se la differenza tra la seconda e la terza non vi é chiara, beh, é buona cosa sapere che non siete da soli.

Altri termini che meritano una chiarificazione in questo contesto sono instanziazione e specializzazione, e dichiarazione nei confornti di definizione.

Proprietà del messaggio

Oltre ai campi standard definiti nell'header di un messaggio, é possibili definire dei campi custom, usando le funzionalità messe a disposizione da JMS per la gestione delle proprietà.

Il nome di una proprietà deve rispettare le regole definite per la sintassi di un selettore.
Una proprietà può assumere valori di tipo boolean, byte, short, int, long, float, double e String.

I valori di una proprietà per un messaggio sono fissati prima della sua spedizione. Per il cliente sono disponibili in sola lettura, il suo tentativo di modificarli risulta in una eccezione di tipo MessageNotWriteableException.

Per iterare la lettura delle proprietà di un messaggio si usi il metodo getPropertyNames() per ottenere un enumeratore dei nomi delle proprietà, e quindi si legga il valore associato per ognuno di essi.

E' possibile eliminare tutti i valori delle proprietà di un messaggio usando il metodo clearProperties().

Cercare di leggere il valore di una proprietà non definita per uno specifico messaggio fa ottenere null come risultato.

I campi dell'intestazione del messaggio

Gran parte dei campi dell'intestazione sono inizializzati dal metodo che lo manda:
  • JMSDestination
  • JMSDeliveryMode
  • JMSExpiration
  • JMSPriority
  • JMSMessageID
  • JMSTimestamp
Altri tre sono settati dal cliente:
  • JMSCorrelationID
  • JMSReplyTo
  • JMSType
E infine il provider setta
  • JMSRedelivered.
L'amministratore del sistema può configurare JMS per dare un valore specifico per JMSDeliveryMode, JMSExpiration e JMSPriority.
  • JMSDestination: destinazione a cui é stato mandato il messaggio.
  • JMSDeliveryMode: modo di spedizione secondo il quale é stato mandato il messaggio.
  • JMSMessageID: identifica univocamente ogni messaggio spedito da un provider
  • JMSTimestamp: é il momento in cui il messaggio é stato passato a un provider per essere spedito.
  • MSCorrelationID: può essere usato dal client per creare una relazione tra messaggi.
  • JMSReplyTo: la destinazione dove si dovrebbe mandare la risposta a un determinato messaggio.
  • JMSRedelivered: settato se il messaggio é stato mandato più volte, e quindi forse già recepito dal client.
  • JMSType: tipo del messaggio.
  • JMSExpiration: Settato a zero nel caso il messaggio sia sempre valido.
  • JMSPriority: priorità dal messaggio definita nell'intervallo [0..9], con 0 ad indicare il valore più basso.

Usare i template

Nel sesto capitolo di C++ Templates: The Complete Guide si fanno alcune utili considerazioni sull'uso pratico delle template.

Nel primo paragrafo si spiega come i dettagli implementativi propri dei template causino un dilemma e, possibilimente, anche degli errori a livello di linkaggio. La soluzione standard é quella del cosiddetto "inclusion model" che consiste in pratica nel mettere dichiarazione della classe template e la sua definizione nello stesso file che viene incluso dal codice che lo usa.

Nel secondo paragrafo si illustra il metodo dell'"instanziazione esplicita" che consiste in pratica nell'indicare esplicitamente quale template si voglia utilizzare, in modo da dare un suggerimento al linker sul lavoro da fare con la classe template. Il problema é che le regole sottese sono davvero poco elastiche: richiedere più di una volta l'esplicita istanziazione di un template porta a errori in fase di linkaggio e definizioni duplicate delle entità instanziate.

E' possibile sviluppare codice aperto alla scelta del modello inclusivo e della instaziazione esplicita due file di include per ogni template, includendo uno o l'altro header a seconda del modello che intendiamo usare. L'opzione viene dettagliata nel sottoparagrafo 6.2.2, a me sembra francamente sorgente di incomprensioni anche in un progetto di media dimensione, e quindi lascerei perdere.

Nel terzo paragrafo si mostra il separation model, in pratica si fa riferimento alla keyword export applicata alla dichiarazione di un template, in modo da renderla utilizzabile al codice seguente anche se la definizione del codice non é visibile. E' da notare che le funzioni inline all'interno di un template non vengono esportate, dato che non é possibile combinare export e inline.

Nonostante questo problema, il modello separativo sembra notevolmente più attraente di quello inclusivo, sfortunatamente ha altre limitazioni. Non molti compilatori supportano la parola chiave export, e quindi il codice scritto in questo modo rischia di non essere portabile. Secondariamente il modello separativo sposta il lavoro dalla fase di compilazione a quella del linkaggio, e nella realtà si scopre spesso che i vantaggi in termini di tempi impiegati per generare l'eseguibile non cambiano sostanzialmente. Inoltre ci possono essere dei problemi a livello semantico, che verranno trattati più avanti nel testo.

Il sesto paragrafo affronta il problema del debug per template. Verificare il funzionamento di un template per ogni possibile tipo sembra un compito impossibile, inoltre la diagnostica per gli errori generati all'interno di un template é a prima vista terrorizzante.

Complicazioni di base sui template

Il quinto capitolo di C++ Templates: The Complete Guide é dedicato ad aspetti dei template che pur essendo di base sono anche un po' spinosi.

Nel primo paragrafo si esplora l'uso di typename e del costrutto .template, situazioni che capiterà di rado di affrontare nella programmazione quotidiana, ma meglio non farsi cogliere impreparati.

Il secondo paragrafo mette sull'avviso nei confronti di una stranezza dei template. Nel caso di classi derivate l'uso di this-> é necessario per riferirsi a dati o metodi della superclasse. Vedremo meglio la faccenda più avanti, nel capitolo nove del libro, ci si assicura.

Il terzo paragrafo ci introduce alla parametrizzazione di membri di template.

Ad esempio, la nostra classe Stack potrebbe essere resa più elastica definendo l'operatore assegnamento in modo parametrico:

template <typename T>
class Stack {
// ...

// assign stack of elements of type T2
template <typename T2>
Stack<T>& operator= (Stack<T2> const&);
};

Ecco a seguire l'implementazione del metodo:

template <typename T>
template <typename T2>
Stack<T>& Stack<T>::operator= (Stack<T2> const& op2)
{
if ((void*)this == (void*)&op2) {
return *this;
}

Stack<T2> tmp(op2); // create a copy of the assigned stack

elems.clear();
while (!tmp.empty()) { // copy all elements
elems.push_front(tmp.top());
tmp.pop();
}
return *this;
}

In questo modo é possibile assegnare uno stack di interi a uno di float.

Nel quarto paragrafo ci si spiega come creare un template con parametri templatizzati. Utile se vogliamo creare, ad esempio, uno stack di cui specifichiamo sia il tipo dei dati trattati che il tipo del container utilizzato per memorizzarli, una cosa così:

Stack<int,std::vector<int> > vStack;

Notevole il quinto paragrafo, dove ci viene spiegato che, in un certo senso, é possibile chiamare una sorta di costruttore di default per i tipi di base. Ovvero, questo codice:

template <typename T>
void foo()
{
T x = T();
}

compila correttamente anche nel caso che T sia un tipo built-in, come ad esempio un int. Stupefacente, sensato, e molto utile. Il valore che viene assegnato é, molto propriamente, zero.

Il sesto paragrafo illustra un problema che, prima o poi capita a tutti: il fatto che l'uso di stringhe letterali risulta un po' ostico in connessione con i template.

Il problema é che una stringa come "apple" ha tipo char const[6], mentre "tomato" ha tipo char const[7] e non, come ci si potrebbe aspettare, lo stesso tipo.

Il paragrafo entra nei dettagli di questo problema fornendo alcune possibili soluzioni.