STL - Abstract Data Types

Il quarto capitolo di Designing Components with the C++ STL, di Ulrich Breymann, é dedicato a stack, queue e priority_queue; e poi ai container associativi ordinati: set,
map, multiset e multimap.

Le classi template presentate qui sono chiamate anche container adaptor perché adattano un interfaccia. Ad esempio quando si usa un oggetto stack si usano i metodi i metodi propri di stack che usano un container che potrebbe essere un vector.

STL - deque

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

Il container deque (double ended queue: coda a doppia terminazione), come vector, permette l'accesso casuale e, come una list, permette l'inserimento e rimozione di elementi agli estremi in tempo costante. Inserimento e rimozione nel suo mezzo sono invece relativamente costosi, O(n).

Metodi aggiuntivi per deque:
  • reference operator[](n), const_reference operator[](n): ritorna una referenza all'ennesimo elemento.
  • reference at(n), const_reference at(n): ritorna una referenza all'ennesimo elemento, o lancia una eccezione.
  • void push_front(const T& t): inserisce un elemento all'inizio.
  • void pop_front(): elimina il primo elemento.

STL - List

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

Il container List ha una serie di metodi aggiuntivi:
  • void merge(list&), void merge(list&, Compare_object): fonde due liste ordinate - complessità O(n). E' possibile specificare la modalità di comparazione.
  • void push_front(const T& t): inserisce un elemento all'inizio.
  • void pop_front(): elimina il primo elemento.
  • void remove(const T& t): elimina tutti gli elementi uguali a t - O(n).
  • void remove_if(Predicate P): elimina tutti gli elementi per cui vale il predicato passato.
  • void reverse(): inverte l'ordine degli elementi nella lista.
  • void sort(), void sort(Compare_object): ordina gli elementi in una lista usando Compare_object o l'operatore < definito per gli elementi. O(n log n).
  • void splice(iterator pos, list& x): sposta il contenuto della lista x prima di pos.
  • void splice(iterator pos, list&x, iterator it): sposta l'elemento di x puntato da it prima di pos.
  • void splice(iterator pos, list& x, iterator first, iterator last): sposta gli elementi di x in [first, last) prima di pos. Se x == this pos deve essere esterno all'intervallo passato.
  • void unique(), void unique(binaryPredicate): elimina gli elementi identici consecutivi, ad eccezione del primo, se applicato ad una lista ordinata lascia solo elementi unici.
Faccio un esempio che riassume, modificando leggermente, gli esempi proposti dal libro:
#include<iostream>
#include<iterator>
#include<list>

using namespace std;

void display(const list<int>& aList) {
list<int>::const_iterator it = aList.begin();
while (it != aList.end())
cout << *it++ << ' ';
cout << "[size is " << aList.size() << ']' << endl;
}

int main() {
list<int> list1;
list<int> list2;
list<int> list3;

for (int i = 0; i < 10; ++i) {
list1.push_front(i * 2);
list2.push_back(i * 2 + 1);
list3.push_back(20 + i);
}
display(list1);
cout << "Sorting:" << endl;
list1.sort();
display(list1);

cout << "The other list:" << endl;
display(list2);

cout << "Merging:" << endl;
list1.merge(list2);
display(list1);
display(list2);

cout << "The third list:" << endl;
display(list3);

cout << "Splice:" << endl;
list<int>::iterator it = list3.begin();
advance(it, 4);
list1.splice(list1.end(), list3, list3.begin(), it);
display(list1);
display(list3);
}
La funzioncina display() ci mostra la scansione sequenziale di una lista via iteratore. Le tre liste sono inizializzate usando push_front() e push_back(), la prima lista viene ordinata usando sort(), dopodichè viene fusa con list2 usando merge(). La terza lista viene utilizzata per farne uno splice() in list1: i suoi primi quattro elementi vengono spostati alla fine di list1.

Una semplice servlet

Continuo la lettura di Head First - Servlets and JSP edito dalla O'Reilly, finisco il primo capitolo affrontando il semplice esempio che lì trova.

Secondo gli autori sarebbe meglio non usare alcun IDE e scriversi tutto a mano. Potrebbero aver ragione, ma é una seccatura immane. Uso perciò Netbeans per semplificarmi la vita.

Creo un nuovo progetto, una Web Application nella categoria Java Web, che chiamo HeadFirstWeb. Come server uso Tomcat 6 e faccio riferimento a Java EE 5.

Nel progetto mi creo una nuova servlet, la cui classe ha nome s01, che metto nel package hf. La servlet ha nome ASimpleServlet e pattern URL /servlet01, confermiamo e andiamo a vedere il codice generato.

web.xml

Il file si trova nel folder WEB-INF e contiene queste informazioni:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>ASimpleServlet</servlet-name>
<servlet-class>hf.s01</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ASimpleServlet</servlet-name>
<url-pattern>/servlet01</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

Ci interessano le sezioni relative alle servlet. Il primo blocco definisce la correlazione tra il nome della servlet, ASimpleServlet, e la sua classe Java di riferimento, hf.s01; nel blocco servlet-mapping vediamo la correlazione tra il nome della servlet e l'URL utilizzata per accederla.

In pratica il nome della servlet fa da tramite tra il nome della classe Java che la implementa e l'indirizzo con cui é possibile richiamarla.

s01.java

Il file si trova nella sezione Source Packages, nel package hf.

Modifichiamo solo leggermente il codice proposto. L'intestazione del file resta tale e quale:

package hf;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

La classe viene definita come una estensione di HttpServlet:

public class s01 extends HttpServlet {

Quello che cambiamo é il metodo processRequest() che viene utilizzato per processare sia POST che GET. In realtà a noi, a questo punto, interesserebbe solo considerare la GET, quindi potremmo semplificare il codice, eliminando la gestione per la POST e spostando il codice definito in processRequest() nel corpo di doGet(). Ma non ci pare un impresa particolarmente utile, e quindi non cambiamo questo codice:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

Nella processRequest() rendiamo attivo il codice che genera una response e facciamo in modo che venga visualizzato il timestamp corrente:

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet s01</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet @ " + new java.util.Date() + "</h1>");
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}

Notiamo che settiamo il tipo di contenuto della response a testo html codificato in UTF-8, e che scriviamo il codice HTML nella response approfittando dell'oggetto PrintWriter che la response ci mette a disposizione.

Notiamo anche che la scrittura sulla response é racchiusa in un blocco try a cui corrisponde un finally in cui chiudiamo il writer. Così anche in caso di eccezioni durante la scrittura chiudiamo correttamente il writer.

Facciamo una build del progetto e otteniamo un .war (Web Archive) che contiene la nostra piccola web application. Ne facciamo un deploy per la nostra installazione Tomcat e possiamo vedere la nostra servlet in azione.

C'é una varietà di modi per eseguire l'installazione di un war su Tomcat. Di solito io faccio così:
  • startup di Tomcat (nel mio caso gli ho riservato la porta 8084)
  • accesso di Tomcat via browser (http://localhost:8084/)
  • accesso del Tomcat Web Application Manager (http://localhost:8084/manager/html). Nota che un utente Tomcat deve avere i privilegi di admin per poter accedere a questa pagina, vedi il file conf/tomcat-users.xml nell'installazione di Tomcat.
  • verso il fondo della pagina c'é la sezione Deploy, sottosezione WAR file to deploy. Basta selezionare il nostro file war, cliccare sul bottone Deploy e il gioco é fatto.


A questo punto per accedere la servlet dovrebbe bastare specificare questo URL:
http://localhost:8084/HeadFirstWeb/servlet01


Il difetto principale di questo approccio, ci fanno notare gli autori del libro, sta nella innaturalità dell'inserimento di codice HTML all'interno di codice Java. Generare una pagina complessa, e mantenerla, diventa un compito veramente spiacevole.

Fortunatamente si può fare il contrario, ovvero inserire codice Java all'interno di HTML, ricorrendo a JSP.

Torniamo al nostro progetto HeadFirstWeb, notiamo che Netbeans ha generato anche un index.jsp nella sezione WebPages. Andiamo a modificarla leggermente, per inserire il codice Java che ci interessa (la generazione del timestamp) e, già che ci siamo, un link alla servlet. Il corpo della pagina diventa questo:

<body>
<h1>Hello World!</h1>
JSP @ <%= new java.util.Date() %>
<br />
<a href="servlet01" target="_blank">Servlet</a>
</body>

Compiliamo, rimuoviamo il vecchio war da Tomcat e installiamo il nuovo e ora, specificando questa URL:
http://localhost:8084/HeadFirstWeb/

Dovremmo vedere la nostra pagina JSP, con link alla servlet che abbiamo creato in precedenza.

Head First - Servlets and JSP

Un buon libro introduttorio su questa parte di Java EE é Head First - Servlets and JSP edito dalla O'Reilly.

Lo leggo e scrivo qui qualche nota, a partire dal capitolo 1: perché usare servlets e JSP?

Il processo: un browser web permette all'utente di richiedere una risorsa (pagina html, immagine, suono, un documento pdf, ...); il server web riceve la richiesta, trova la risorsa e ritorna qualcosa all'utente.

Se non la trova l'utente ottiene l'errore 404 Not Found.

Il meccanismo richiesta (request) risposta (response) é gestito via HTTP per mezzo di metodi, i più comuni tra i quali sono GET e POST.
  • GET: semplice richiesta al server per una risorsa.
  • POST: é una richiesta a cui sono associati dei parametri.
In realtà é possibile mandare dati al server anche via GET ma non é solitamente una buona idea, dato che:
  • il numero di caratteri che si possono mandare é basso, e dipendente dal server;
  • i dati mandati via GET sono appesi all'URL, sono quindi visibili all'utente;
D'altro canto, se si vuole ripetere spesso una richiesta parametrizzata, per una GET si può creare un bookmark, mentre con la POST occorre rieseguire la pagina in cui sono settati i parametri.

Per una GET la richiesta é strutturata in questo modo:

Request line:
GET [path]?[param1]&[param2]& ... [paramN] HTTP/1.1

Request headers:
Host: ...

Per una POST, invece, le cose funzionano così:

Request line:
POST [path] HTTP/1.1

Request headers:
Host: ...
...
Accept: text/html, ...
...

Message body (o "payload"):
[param1]&[param2]& ... [paramN]

La risposta HTTP é strutturata così:

Response Headers:
HTTP/1.1 200 OK
Set-Cookie: ...
Content-Type: text/html
...

Response body:
<html>
...
</html>

Il Content-Type indica il tipo (MIME) che identifica la risorsa reperita. Vedi anche il campo Accept della request.

La richiesta di pagine web statiche é gestita direttamente dall'applicazione web server. Nel caso di richiesta di pagine dinamiche, si appoggia ad un altra applicazione sul server.

Le applicazioni classiche che si occupano della generazione di pagine dinamiche sono programmi CGI (Common Gateway Interface) scritti tipicamente in Perl, C, Python e PHP. Per Java si parla di servlet e JSP.

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.