STL - Vector

Dal terzo capitolo di Designing Components with the C++ STL, di Ulrich Breymann, dedicato ai container.

Vediamo un esempio di uso di vettori.

Creiamo un vettore di interi specificandone la dimensione. Se non si specifica il valore con cui vogliamo inizializzarlo, si usa zero come default.

Usiamo il metodo size() per reperire la dimensione del vettore; aggiungiamo un elemento con insert(), incrementando la dimensione del vettore; scandiamo il vettore usando un iteratore; infine scambiamo il contenuto di due vettori usando swap().

#include<vector>
#include<iostream>
using namespace std;

int main() {
vector<int> vectA(10);

cout << "A vector of int is initialized with 0" << endl;
for (size_t i = 0; i < vectA.size(); ++i)
cout << vectA[i] << ' ';
cout << endl;

// fill vector, random access
for (size_t i = 0; i < vectA.size(); ++i)
vectA[i] = i;

// vector increases on demand, append the number 100
vectA.insert(vectA.end(), 100);

// use as array
for (size_t i = 0; i < vectA.size(); ++i)
cout << vectA[i] << ' ';
cout << endl;

for (vector<int>::iterator it = vectA.begin(); it != vectA.end(); ++it)
cout << *it << ' ';
cout << endl;

vector<int> vectB(20);
cout << "\nvectB = ";
for (size_t i = 0; i < vectB.size(); ++i)
cout << vectB[i] << ' ';
cout << endl;

// swap(): a very fast method for swapping two vectors.
vectB.swap(vectA);
cout << "\nvectB after swapping = ";
for (size_t i = 0; i < vectB.size(); ++i)
cout << vectB[i] << ' ';
cout << "\n\nvectA = ";
for (size_t i = 0; i < vectA.size(); ++i)
cout << vectA[i] << ' ';
cout << endl;
}

Un altro esempio con un vettore di stringhe. Non specificando il valore da copiare, si usa come default la stringa vuota. Vediamo poi come insert() e erase() cambino la dimensione del vettore. Finiamo iterando a rovescio sul vettore.

#include<vector>
#include<iostream>
#include<string>

using namespace std;

int main() {
vector<string> vect(4);

cout << "A string vector is initialized with empty strings: ";
for (size_t i = 0; i < vect.size(); ++i)
cout << '"' << vect[i] << "\" ";
cout << endl;

vect[0] = "First";
vect[1] = "Second";
vect[2] = "Third";
vect[3] = "Fourth";

cout << "Setting values: ";
for (size_t i = 0; i < vect.size(); ++i)
cout << '"' << vect[i] << "\" ";
cout << endl;

vect.insert(vect.end(), "Last");
cout << "Inserting increases the size: " << vect.size() << endl;

vector<string>::iterator it = ++vect.begin();
cout << "Erasing the element next to begin: " << *it << endl;
vect.erase(it);

cout << "Inserting reduces the size: " << vect.size() << endl;
for (it = vect.begin(); it != vect.end(); ++it)
cout << '"' << *it << "\" ";
cout << endl;

cout << "Iterating backwards: ";
typedef vector<string>::reverse_iterator rev_it;
for (rev_it rit = vect.rbegin(); rit != vect.rend(); ++rit)
cout << '"' << *rit << "\" ";
cout << endl;
}

Si noti che il costo di una inserizione o rimozione alla fine del vettore ha costo costante, O(1), altrimenti bisogna tener conto che gli indici devono essere riallineati, causando un costo proporzionale al numero di elementi che devono essere spostati, O(n).

Tomcat: installazione

Apache Tomcat é un container per servlet e JSP. La versione 6 di Tomcat implementa le specificazioni Servlet 2.5 e JSP 2.1 e include funzionalità che lo rendono una utile piattaforma per lo sviluppo e la distribuzione di applicazioni web e servizi web.

Struttura delle directory

La radice dell'installazione é messa nella variabile di ambiente CATALINA_HOME, sotto questa directory troviamo:
  • bin: startup, shutdown e altri script
  • conf: file di configurazione
  • logs: destinazione di default per i file di log
  • webapps: qui si mettono le nostre applicazioni web
Dato che mi sono installato Tomcat su una macchina Windows Vista, mi sono scritto un file batch per preparare l'esecuzione dell'applicativo settando alcune variabili d'ambiente:
set PATH=%PATH%;C:\Program Files\Apache\Tomcat6.0.xx\bin;
set JAVA_HOME=C:\Program Files\Java\jdk1.6.0_xx
set CATALINA_HOME=C:\Program Files\Apache\Tomcat6.0.xx
set CATALINA_BASE=C:\dev\tomcat
Definisco CATALINA_BASE per non dover dare a Tomcat i privilegi di amministratore, che sarebbero necessari per accedere in read/write ai file dove i programmi sono installati. Questo mi obbliga però a copiare la struttura vista sopra (a parte bin) in questa altra directory.

STL - Container

Dal terzo capitolo di Designing Components with the C++ STL, di Ulrich Breymann, dedicato ai container.

Un container é un oggetto che é usato per gestire altri oggetti che in questo contesto sono detti elementi del container. Si occupa di allocare e deallocare memoria e di controllare l'inserimento e la rimozione degli elementi.

In questo capitolo sono descritti tre container: vector, list e deque.

Metodi di un container

Ogni container mette a disposizione un insieme di metodi. Eccone un elenco, dove X é il nome del tipo del container:
  • X(): default ctor; crea un container vuoto;
  • X(const X&): copy ctor;
  • ~X(): dtor; chiama il dtor di tutti gli elementi del container;
  • iterator begin(), const_iterator begin(): inizio del container;
  • iterator end(), const_iterator end(): posizione dopo l'ultimo elemento;
  • size_type max_size(): massima dimensione del container;
  • size_type size(): dimensione corrente del container, calcolata come la distanza tra begin() e end();
  • bool empty(): equivalente a size() == 0 o begin() == end();
  • void swap(X&): scambio con il container passato;
  • X& operator=(const X&): operatore di assegnamento;
  • bool operator==(const X&);
  • bool operator!=(const X&);
  • bool operator<(const X&);
  • bool operator>(const X&);
  • bool operator<=(const X&);
  • bool operator>=(const X&);
Per un container reversibile sono disponibili anche interatori inversi e i metodi rbegin() e rend().

Sequenze

Una sequenza é un container i cui elementi sono posizionati in modo strettamente lineare.

Questi sono i metodi aggiuntivi per una sequenza:
  • X(n, t): crea una sequenza con n copie di t;
  • X(i, j): crea una sequenza con gli elementi nell'intervallo [i, j) copiati nella nuova sequenza;
  • iterator insert(p, t): inserisce una copia di t prima della locazione p, ritorna il puntatore al nuovo elemento;
  • void insert(p, n, t): inserisce n copie di t prima di p;
  • void insert(p, i, j): inserisce le copie degli elementi nell'intervallo [i, j) prima di p;
  • iterator erase(q): elimina l'elemento puntato da q, ritorna il puntatore alla posizione seguente a q, o end();
  • iterator erase(q1, q2): elimina gli elementi nell'intervallo [q1, q2), ritorna il puntatore a q2, che può essere anche end();
  • void clear(): elimina tutti gli elementi, equivale a erase(begin(), end());
Nella STL ci sono tre tipi di container sequenziali: vector, list e deque.

La lista permette di gestire efficientemente le inserzioni e eliminazioni nel mezzo del container, la doppia coda (deque = double ended queue) é utile nel caso si operi prevalentemente sugli estremi, vector corrisponde all'array. L'accesso casuale é supportato da array e deque.

Altri metodi disponibili:
  • void assign(n, t = T()): rimuove gli elementi del container e poi inserisce n elementi t;
  • void assign(i, j): rimuove gli elementi del container e poi inserisce gli elementi nell'intervallo [i, j).
  • reference front(), const_reference front(): fornisce una reference al primo elemento del container;
  • reference back(), const_reference back(): fornisce una reference all'ultimo elemento del container;
  • void push_back(t): inserisce t alla fine;
  • void pop_back(): elimina l'ultimo elemento;
  • void resize(n, t = T()): cambia la dimensione del container, elementi vengono aggiunti o eliminati alla fine del container;
  • reverse_iterator rbegin(), const_reverse_iterator rbegin(): iteratore iniziale per la scansione al contrario;
  • reverse_iterator rend(), const_reverse_iterator rend(): iteratore finale per la scansione del container al contrario;

STL - Iteratori su ostream

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

Il secondo paragrafo é dedicato agli iteratori su stream, usati per lavorare direttamente sugli stream di input e output.

L'iteratore per l'ostream ostream_iterator usa l'operatore = all'elemento ottenuto per dereferenziazione allo scopo di scrivere elementi di tipo T. Elementi consecutivi sono normalmente scritti direttamente nello stream, uno dopo l'altro, senza separatori. Di solito questa non é una buona idea, dato che il risultato é spesso illeggibile.

Per evitare questo é possibile passare un parametro di tipo char* al costruttore dell'iteratore. Quella stringa verrà utilizzata come separatore dopo ogni elemento.

Faccio qui un esempio minimale, mentre quello del libro si diffonde su come gestire tipi complessi:

#include<fstream>
#include<iterator>

using namespace std;

int main() {
ofstream target("output.txt");
ostream_iterator<int> pos(target, "\n");
for(int i = 0; i < 10; ++i) {
*pos++ = i;
}
}

Da notare l'idioma utilizzato che prevede l'uso dell'operatore di postincremento sull'iteratore, anche se questo in realtà non fa nulla, per ragioni di omogenità con l'uso degli iteratori di output in altri contesti.

STL - Iteratori su istream

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

Il secondo paragrafo é dedicato agli iteratori su stream, usati per lavorare direttamente sugli stream di input e output.

L'iteratore per l'istream istream_iterator usa l'operatore >> per leggere elementi di tipo T con la proprietà che gli spazi bianchi (ovvero spazi, tabulatori, andate a capo) sono ignorati quando trovati prima di un elemento e interpretati come separatori quando trovati tra due elementi.

Quando viene costruito e con ogni avanzamento per mezzo dell'operatore ++ l'iteratore legge un elemento di tipo T. Alla fine dello stream l'iteratore diventa uguale all'iteratore end().

Ecco un esempio di lettura da file usando questo iteratore:

#include<fstream>
#include<iostream>
#include<iterator>
#include<string>

using namespace std;

int main() {
ifstream source("d221.cpp");

istream_iterator<string> pos(source);
istream_iterator<string> end;

if(pos == end) {
cout << "File not found!" << endl;
return -1;
}

while(pos != end) {
cout << *pos << endl;
++pos;
}
}

I Web Service RESTful

Note dalla lettura di Beginning Java EE 6 Platform with GlassFish 3 di Antonio Goncalves. Capitolo 15 - I Web Service RESTful

REST sta per Representational State Transfer e indica uno stile architetturale basato su come funziona il web. Per supportare questo stile nello sviluppo di web service, Java mette a disposizione JAX-RS (Java API for RESTful Web Services).

In REST ogni informazione é una risorsa, e di fa a riferimento a queste risorse usando URI (Uniform Resource Identifier), tipicamente link nel web.

HTTP

Lo stile architetturale REST client-server é progettato per usare un protocollo di comunicazione stateless, tipicamente HTTP.

Il client manda un richiesta al server, aspettandosi una risposta. La risposta é costituita da un codice (p.es.: 200 OK); un certo numero di header, tra cui il content-type che tipicamente é txt/html, ma può anche essere application/xml o image/jpeg; e la rappresentazione.

I principale metodi HTTP sono:
  • GET: per leggere una rappresentazione della risorsa. Dovrebbe essere implementato in modo sicuro, ovvero non dovrebbe cambiare lo stato della risorsa, e idempotente, ovvero chiamare più volte get per la stessa risorsa dovrebbe lasciare la risorsa nello stesso stato.
  • POST: crea una nuova risorsa come subordinata ad una risorsa principale identificata dalla URI richiesta. Di conseguenza non é sicura, dato che la risorsa é aggiornata, né idempotente.
  • PUT: aggiorna lo stato di una risorsa memorizzata ad un dato URI. Non é sicura ma é idempotente.
  • DELETE: richiede l'eleminazione della risorsa. É quindi idempotente ma non sicura.
Altre azioni HTTP sono:
  • HEAD: simile a GET, ma non ritorna il corpo del messaggio.
  • TRACE: ritorna una eco della richiesta ricevuta.
  • OPTIONS: é una richiesta di informazioni sulle opzioni di comunicazione disponibili.
  • CONNECT: usata in congiunzione con un proxy per usare il protocollo HTTP come wrapper per altri protocolli di rete per gestire il tunnelling.
Tipi di contenuto

I principali tipi di media internet, quelli che erano orginalmente chiamati tipi MIME) utilizzati sono
  • text/html
  • text/plain: testo semplice, é il default.
  • image/gif, image/jpeg, image/png
  • text/xml, application/xml
  • application/json: JSON, che sta per JavaScript Object Notation, é un formato di testo usato per lo scambio di dati per linguaggi di programmazione.
Codici di stato
  • 1xx: informazionale
  • 2xx: successo; ad es. 200 OK
  • 3xx: ridirezione; ad es. 301 Moved Permanently
  • 4xx: errore lato client; ad es. 404 Not Found
  • 5xx: errore lato server; ad es. 500 Internal Server Error
L'implementazione di riferimento di JAX-RS é Jersey.

STL - Iteratori inversi

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

Un iteratore inverso si muove all'indietro in un container usando l'operatore ++. L'inizio e la fine di un container per un iteratore inverso sono marcati dalle funzioni rbegin() (punta all'ultimo elemento) e rend() (punta a prima dell'inizio).

La funzione base() ritorna la posizione corrente come un iteratore bidirezionale.

Ci sono due tipi di iteratori inversi:
  • bidirezionale: praticamente uguale a un iteratore "normale" bidirezionale, con gli operatori ++ e -- che operano come reciproci.
  • accesso causale: estende l'iteratore inverso bidirezionale con operazioni aritmetiche che permettono di muoversi a salti nel container.

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.