Open Source im professionellen Einsatz
Linux-Magazin 01/2014
© nomadsoul1, 123RF.com

© nomadsoul1, 123RF.com

Webanwendungen in C++ mit Tntnet

Web plus plus

,

Angeregt durch die "Reifeprüfung fürs Web" im Linux-Magazin 11/13 stellt dieser Artikel das Webframework Tntnet vor. Mit ihm lassen sich in C++ Webanwendungen mit MVC-Architektur programmieren.

1333

Im Magazin-Schwerpunkt 11/13 [1] durften Contao, Rails, Django und Magnolia CMS zeigen, wie sie eine Programmieraufgabe lösen. Das inspirierte die Autoren, die Beispielanwendung für diesen Artikel in C++ umzusetzen. Der Online-Veranstaltungskalender (Abbildung 1) zapft eine Open-Data-Schnittstelle an, um Straßenfeste anzuzeigen, die in einem vom Anwender gewählten Zeitraum stattfinden.

DELUG-DVD

Auf der DELUG-DVD zu dieser Ausgabe finden Sie die Aufgabenstellung sowie die Auswertung aus dem Schwerpunkt "Reifeprüfung fürs Web" im Magazin 11/13.

Abbildung 1: Dank Tntnet lässt sich die Website für die Veranstaltungssuche auch in C++ programmieren.

Als Grundlage dient nun Tntnet [2], Tommi Mäkitalos C++-Framework für Webanwendungen, das unter LGPLv2.1 steht. Im Jahr 2003 veröffentlichte er die erste Version, derzeit ist die Release 2.2 aktuell. Tntnet-Anwendungen laufen etwa bei der Deutschen Börse AG, Tommis Arbeitgeber. Dieser Artikel verwendet die jüngste Version aus dem Entwickler-Repository, die der Kasten "Tntnet installieren" einrichtet.

Tntnet installieren

Das Webframework Tntnet [2] setzt die Bibliothek Cxx-Tools voraus, die ebenfalls vom Entwickler Tommi Mäkitalo stammt. Zur Installation klont man deren Code von einem Github-Repository [4]. Im entstandenen Verzeichnis konfigurieren und übersetzen die folgenden Kommandos den Code:

autoreconf -i
./configure
make

Das Kommando »su -c 'make install'« installiert die Tools. Ebenso lässt sich Tntnet von [5] klonen und mit den gleichen Kommandos einsatzbereit machen.

Ob Tntnet funktioniert, lässt sich mit einer einfachen Beispielanwendung testen. In einem beliebigen Verzeichnis erzeugt folgender Befehl die Grundlage für die Webanwendung »myfirstproject« :

tntnet-config --project=myfirstproject

Im Verzeichnis »myfirstproject/« stößt »make« die Übersetzung an. Anschließend startet das Kommando »tntnet« die Anwendung samt eingebautem Webserver, der sich mit Logmeldungen bemerkbar macht (Abbildung 2). Im Browser ist das Projekt unter »http://localhost:8000/myfirstproject« zu erreichen.

Abbildung 2: Installation geglückt: Tntnet schreibt sein HTTP-Access- und das Error-Protokoll auf das Terminal.

C++ als Technologie für Webanwendungen ist im Vergleich zu Ruby on Rails und anderen Skriptsprachen sehr Ressourcen-schonend. So lassen sich damit auch Weboberflächen für die schwächeren CPUs von Embedded-Geräten verwirklichen. Am anderen Ende des Spektrums ist es für hohe Lasten skalierbar und unterstützt Multithreading. Zudem ist C++ seit etwa drei Jahrzehnten ein fester Bestandteil der IT-Welt und international standardisiert. Das macht Tntnet zukunftssicher: Anwender können darauf vertrauen, dass der Code wartbar bleibt.

Flexibel

Tntnet unterscheidet sich in einem Punkt wesentlich von verbreiteten Webframeworks wie Rails oder Django: Es propagiert nicht das Prinzip "Konvention vor Konfiguration". Es möchte dem Anwender nicht vorschreiben, wie er sein Projekt zu organisieren und seine Dateien zu benennen hat, sondern versucht über dokumentierte Best Practice und Howtos einen Leitfaden für die Realisierung guter Software zu geben [3].

Tntnet-Applikationen lassen sich grundsätzlich auf zwei Arten umsetzen. Entweder kommt ein Tntnet-Application-Server zum Einsatz, um Shared Libraries und Objektdateien zu laden und auszuführen, oder man erzeugt ein einziges lauffähiges Binary. Im ersten Fall besteht die Applikation aus einer Shared Library und dem Tntnet-Application-Server. Im zweiten Fall lässt sich alles zu einer einzigen ausführbaren Datei zusammenfassen, was das Ausrollen vereinfacht, etwa auf Embedded-Geräten. Dieser Artikel verwendet die zweite Variante.

Zur Ansicht

Das Tntnet-Framework nutzt die verbreitete Anwendungsarchitektur Model View Controller (MVC). Für die View-Komponente, die für Ansichten zuständig ist, sieht es die projekteigene Auszeichnungssprache ECPP vor, die C++ über spezielle Tags in HTML einbettet. Beim Übersetzen wandelt ein Präprozessor sie in C++-Code um, den ein herkömmlicher C++-Compiler zu einer ausführbaren Datei kompilieren kann. Es wäre möglich, die gesamte Logik als C++-Code in HTML einzubetten. Bei kleineren Aufgaben führt das rasch zu einem Resultat, schon bei etwas umfangreicheren Projekten ist es aber nicht ratsam.

Getreu dem MVC-Prinzip ist in der Suchseite (Listing 1) kaum Logik zu finden, denn sie dient ausschließlich der Ansicht. Die Datei »strassenfeste.ecpp« deklariert zu Beginn mit »<%args>« die Anfrage-Parameter der Veranstaltungssuche. Die unterschiedlichen »scope« -Tags klären die Geltungsbereiche von Variablen innerhalb der Anwendung, einer Session und eines HTTP-Requests. Daneben befüllt die Datei das Suchformular mit den Bezirken und gibt Ergebnisse aus, sofern die Suche welche ergab.

Listing 1

strassenfeste.ecpp (gekürzt)

01 <%args>
02    q;
03    bezirk;
04 [...]
05 </%args>
06 <%application scope="shared">
07     std::vector<std::string> bezirke;
08 </%application>
09 <%request scope="shared" include="strassenfestresult.h">
10     StrassenfestResult strassenfestResult;
11 </%request>
12 <%session scope="shared" include="suchesession.h">
13     SucheSession suche;
14 </%session>
15 [...]
16 <h1>Suche</h1>
17
18 <form>
19  <table class="form">
20   <tr>
21     <th>Stichwortsuche:</th>
22     <td><input type="text" name="q" value="<$q$>"></td>
23   </tr>
24   <tr>
25    <th>Bezirk:</th>
26    <td>
27     <select name="bezirk">
28 % for (unsigned n = 0; n < bezirke.size(); ++n) {
29      <option value="<$ bezirke[n] $>"<? bezirk == bezirke[n] ? " selected"?>><$
30 bezirke[n] $></option>
31 % }
32     </select>
33    </td>
34   </tr>
35 [...]
36  </table>
37
38 % if (strassenfeste.empty()) {
39 Keine Ergebnisse
40 % } else {
41 [...]
42 % }

Im Session-Scope referenziert die ECPP-Datei zudem den Header »suchesession.h« , der die Klassen der Anwendung bekannt macht. Daneben deklariert sie die gemeinsame Variable »suche« , die die Such-Session für alle Komponenten speichert. Damit verknüpft sie auch die View mit dem Controller, der die eigentliche Arbeit macht.

Die Funktion des Controllers übernimmt der Code in »controller/suche.cpp« , gewöhnlicher C++-Code ohne besondere Tags (Listing 2). Es gibt allerdings keine Headerdatei, sodass der Anwendungsentwickler die Instanzierung indirekt durch eine Tntnet-Factory-Klasse erledigt (Zeile 21). Der Controller erbt von der Klasse »tnt::Component« , die grundlegende Funktionen eines Controllers bereitstellt.

Listing 2

Controller controller/suche.cpp

01 #include <sstream>
02 #include <tnt/component.h>
03 #include <tnt/componentfactory.h>
04 #include <tnt/httprequest.h>
05 #include <tnt/httpreply.h>
06 #include <cxxtools/log.h>
07 #include <strassenfestresult.h>
08 #include <strassenfestmanager.h>
09 #include <suchesession.h>
10
11 log_define("suche.controller")
12
13 namespace
14 {
15   class sucheController : public tnt::Component
16   {
17     public:
18       unsigned operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams& qparam);
19   };
20
21   static tnt::ComponentFactoryImpl<sucheController> factory("controller/suche");
22
23   unsigned sucheController::operator() (tnt::HttpRequest& request, tnt::HttpReply& reply, tnt::QueryParams& qparam)
24   {
25     TNT_APPLICATION_SHARED_VAR(std::vector<std::string>, bezirke, ());
26     TNT_REQUEST_SHARED_VAR(StrassenfestResult, strassenfestResult, ());
27
28     TNT_SESSION_SHARED_VAR(SucheSession, suche, ());
29
30     log_debug("sucheController; q=" << qparam.getUrl());
31
32     StrassenfestManager manager;
33
34     if (bezirke.empty())
35     {
36       bezirke = manager.getBezirke();
37     }
38
39     if (qparam.arg<bool>("suchen"))
40     {
41       log_debug("suchen");
42
43       suche.q        = qparam.arg<std::string>("q");
44       suche.bezirk   = qparam.arg<std::string>("bezirk");
45
46       suche.von_from = qparam.arg<std::string>("von_from");
47       suche.von_to   = qparam.arg<std::string>("von_to");
48
49       if (!suche.von_from.empty())
50         suche.from = cxxtools::Date(suche.von_from, "%d.%m.%Y");
51
52       if (!suche.von_to.empty())
53         suche.to = cxxtools::Date(suche.von_to, "%d.%m.%Y");
54
55       suche.pageNo = 1;
56       strassenfestResult = manager.search(suche.q, suche.bezirk, suche.from, suche.to,
57         cxxtools::Date(), suche.itemsPerPage, suche.pageNo);
58     }
59     else if (qparam.arg<bool>("previousPage"))
60     {
61       --suche.pageNo;
62       strassenfestResult = manager.search(suche.q, suche.bezirk, suche.from, suche.to,
63         cxxtools::Date(), suche.itemsPerPage, suche.pageNo);
64     }
65     else if (qparam.arg<bool>("nextPage"))
66     {
67       ++suche.pageNo;
68       strassenfestResult = manager.search(suche.q, suche.bezirk, suche.from, suche.to,
69         cxxtools::Date(), suche.itemsPerPage, suche.pageNo);
70     }
71
72     // Return DECLINED to tell tntnet to continue processing with next
73     // mapping. The next mapping will be the corresponding view.
74
75     return DECLINED;
76   }
77
78 }

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 5 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • C++ fürs Web: Tntnet 2.0 und Cxxtools 2.0

    Mit dem Webserver Tntnet lassen sich Webanwendungen in C++ programmieren. Nach über zwei Jahren ohne stabile Releases gibt es den Server sowie die verwandte Bibliothek Cxxtools nun in neuen Versionen.

  • Magnolia CMS

    Magnolia CMS nutzen große Anwender wie Lovefilm oder EADS für ihre Webpräsenz. Das freie Java-System importiert externe Daten in ein zentrales Content Repository und macht sie damit auch bearbeitbar.

comments powered by Disqus

Ausgabe 04/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.