documentation de libapache2-mod-raii

Quel éditeur de texte utiliser

Je dirais gedit. J'y ai ajouté le support des pages CSP. Par ailleurs, dans le répertoire debian du tarball il y a un fichier cpp.lang que vous pouvez copier dans le répertoire /usr/share/gtksourceview-2.0/language-specs/ afin de profiter de quelques aménagements propre à mod_raii.

Aussi kdevelop qui est assez paramétrable et s'intègre assez bien si l'on prend soint de définir les macros SERVLET, exportServlet et les chemins vers les sources.

Démarrer un projet

Tout d'abord, vous devez télécharger et décompresser les source de libapache2-mod-raii. Ensuite copier le répertoire contenant les fichiers du projet minimum dans un répertoire de votre choix. Déterminer un répertoire web pour votre appli et procéder aux adaptations comme suit.

cp /srv/src/libapache2-mod-raii/template/FLatProject /srv/src/appliweb
cd /srv/src/appliweb
./rename.sh appliweb
su0 ln -s $PWD/appliweb.conf /etc/apache2/conf.d/
make
su0 apache2ctl restart
iceweasel http://localhost/appliweb/

Écriture de servlets

La création votre servlet nécessite  la surcharge de la class raii::HttpServlet.

Dans cette classe vous devez soit surcharger la méthode service(HttpServletRequest& request, HttpServletResponse& response), soit les méthodes doDelete, doGet, doHead, doOptions, doPost, doPut, doTrace ou doLastModified.

La méthode service est appelée pour tout les types de requète HTTP tandis que les autres méthodes sont appelées par la méthode service originale selon le type de requête HTTP.

La surcharge peut se faire directement de la façon suivante :

#include <raii.H>

using namespace raii;

class SERVLET(maservlet) : public HttpServlet {

//constructeur par défaut, facultatif
//SERVLET(maservlet)() : HttpServlet() {}
        void service(HttpServletRequest& request, HttpServletResponse& response) {
response << "<html><body>hello world</body></html>";
       }
};

exportServlet(maservlet);


Ou indirectement par l'intermédiaire d'une classe d'abstraction supplémentaire :

#include <raii.H>

using namespace raii;

class MaServletPerso : public Httpservlet {
ptr<HttpSession> session;
String action;
public:
MaServletPerso() : HttpServlet(), session(NULL), action("") {}
protected:
void preService(HttpServletRequest& request, HttpServletResponse& response) {
session=request.getSession();
action=request.getParameter("action");
}
void postService(HttpServletRequest& request, HttpServletResponse& response) {
session=NULL;
action="";
}
};

class SERVLET(maservlet) : public MaServletPerso {

//constructeur par défaut, facultatif
//SERVLET(maservlet)() : MaServletPerso() {}
        void service(HttpServletRequest& request, HttpServletResponse& response) {
response << "<html><body>hello world</body></html>";
       }
};

exportServlet(maservlet);

Notez la nécessité d'utiliser les macros SERVLET() et exportServlet() qui permettent de fournir le point d'entrée de votre servlet.

Par ailleurs, si vous omettez de surcharger HttpServlet, vous obtiendrez l'excetion suivante :

raii::error::SegmentationFault*

Signal (11) : Segmentation Violation: Invalid permissions for mapped object. [0x7f330bbf7f08]

Exception: raii::error::SegmentationFault*
at __restore_rt
binary: /lib/libpthread.so.0
at ??
binary: /lib/libc.so.6

Avouez que ce n'est pas très causant...

Règles de bonne conduite, le modèle MVC.

Lors de la création de votre logiciel web, afin de faciliter la maintenance de votre application, je vous recommande de respecter le modèle MVC. Créez vos classes relatives au modèle dans des fichiers .H dans le répertoire du projet de votre choix (sauf dans les répertoires web). Développez vos controlleurs à l'aide de servlets .C et développez vos vues à l'aide de page .csp.

N'envoyez pas de liens directement sur les page .csp (tel que /projet/view/client_liste.csp) mais utilisez plutôt des liens vers /projet/client.C?action=list par exemple. Ainsi dans votre controleur vous pouvez coder la section suivante :

  if ( action == "list" ) {
request.getRequestDispatcher("/view/client_liste.csp").forward(request,response);
}

Lorsque vous envoyez au controleur une action modifiant l'état interne de l'application utilisez une redirection http une fois que l'état a été modifié au lieu d'un forward direct. Cette redirection doit de nouveau cibler le controleur, pas la vue. Ainsi si le client recharge la page, l'ordre de mise à jour n'est pas transmis une nouvelle fois (c'est important).

N'oubliez pas, n'exposez pas vos vues.

  if ( action == "update" ) {
//code de mise à jour de l'état interne
response.sendRedirect(response.encodeRedirectURL(request.getContextPath()+"/client.C?action=list"));
}

 

Aussi, bien que le modèle MVC permette l'interrogation du modèle par les vues, la plupart du temps vous devrez le faire depuis les controleurs. Les données récoltées devront être transmises aux vues à l'aide des fonctions void request.setAttribute(const String& key, ptr<raii::Object> obj) et ptr<raii::Object> request.getAttribute(const String& key). C'est pour cette raison que vos classes devront hériter de raii::Object.

 

Quand devez-vous redémarrer apache ?

Vous devez redémarrer apache dans les cas suivants :

Options de compilation

Si vous devez fournir des options supplémentaires à g++ lors de la compilation de vos servlets et pages CSP, vous pouvez créer un fichier .build dans le répertoire contenant vos pages. Ce fichier peut contenir plusieurs lignes.

Fichier .build de la galerie Not So Original

-fopenmp -Wall -Werror -O9 
-I/usr/include/ImageMagick -lMagick++
-lGallery_model
-I/usr/include/exiv2 -lexiv2
-Wl,-rpath,/srv/src/gallery -L/srv/src/gallery
-I/srv/src

Notez que si votre projet contient plusieurs répertoires de servlets et de page CSP, il faut reporter ce fichier dans chacun des répertoire. Vous pouvez le faire à l'aide de liens symboliques.

 

Le préprocesseur de pages CSP

Accéder à la page de documentation du préprocesseur raiipp.

 

Connexions aux bases de données

URL de connexion par défaut

Dans le fichier de configuration apache relatif à votre projet vous devez définir une URL de connexion par défaut. C'est cette connexion qui sera utilisée lorsque vous créerez une instance de la classe Connection.

Pour une connexion SQLite2

SqlConnection "sqlite:///chemin/vers/le/fichier.db"

Pour une connexion PostgreSQL

SqlConnection "pgsql://utilisateur:motdepasse@serveur?basededonnées"

Pour une connexion SQLRelay

SqlConnection "sqlrelay://utilisateur:motdepasse@serveur:port/chemin/vers/socket"

Utilisation de Connection et ResultSet dans votre code

Lorsque vous instanciez sans paramètre la classe Connection, la connextion définie dans le fichier de configuration apache est utilisé. Vous pouvez aussi spécifier une autre URL de connection via le constructeur de Connection.

Une fois que votre connexion est obtenue, vous pouvez lancer de requêtes SQL

Connection conn;
ResultSet rs = conn.query("SELECT nom,prenom FROM utilisateurs");

Afin d'éviter les injections SQL vous pouvez utiliser String Connection::sqlize(const String& str);

conn.query("UPDATE utilisateurs SET name='"+conn.sqlize(name)+"' WHERE id="+itostring(id));

Pour parcourir le courseur :

while ( rs.next() ) {
response << "Nom : " << rs["nom"].escapeHTML() << "<br/>\n"
<< "Prénom : " << rs["prenom"].escapeHTML() << "<br/>\n"
<< "<hr/>\n";
}

Notez que l'operateur String ResultSet::operator[](const String& attrName) ne renvoi que des chaînes de caractères.

Si vous devez controller la nullité d'une valeur utilisez rs["champ"].isNull().

Les classes

Documentation générée par doxygen