Schwere Geburt
Wer denkt, Cocoon sei ein Club, ein Label oder ein Film, für den wird dieser Beitrag eine harte Nuss, es geht nämlich um Cocoon, das Web-Entwicklungs-Framework. Mit dem habe ich mich die letzten Tage und Wochen um die Ohren geschlagen und dabei Schritt für Schritt die Schwierigkeit erhöht. Problematisch erweist sich dabei, dass mit wachsender Schwierigkeit auch die Zahl der Webseiten sinkt, die einem weiterhelfen.
Level 1: May I introduce myself?
Um unsere Intranetabfrage vor unerlaubten Zugriffen zu schützen, sollte eine Authentifizierung integriert werden, die Abteilungen erlaubt, darauf zuzugreifen bzw. den Zugriff zu verhindern. Kein Problem – In der Dokumentation zum Cocoon gibt es eine Sektion, die Schritt für Schritt das Einrichten der Authenfizierung erläutert und wo man an welcher Stelle drehen muss, um ein bestimmtes Ergebnis zu erreichen.
Der Abruf einer Webseite beim Cocoon gliedert sich in drei Teile:
- Erzeugen der Daten (z.B. Datenbankabfrage)
- Transformation der Daten (optional)
- “Ausgabe” der Daten
Diese Abfolge wird im Cocoon Pipeline genannt und bleibt für den Anwender völlig unsichtbar – er ruft nur eine Webseite auf, nach deren Namen die entsprechende Pipeline aufgerufen wird. Zur Authentifizierung wird um diese Abfolge ein Päckchen geschnürt, das den Zugriff schützt, der Handler. Der Authentifizierungshandler kennt zwei Pipelines: das Login und die Überprüfung der Nutzerdaten. Ist ein Nutzer eingeloggt, wird nur noch geprüft, ob der Nutzer eingeloggt ist und er auf die Daten zugreifen darf. Also integrierte ich anhand des Beispiels den Handler und ließ die Authentifikation gegen eine XML-Datei laufen. Wie gesagt, ganz einfach…
Level 2: Bürger, ihren Ausweis bitte!
Zur Überprüfung der Login-Daten sollte unser LDAP-Server dienen. Auch hier gab es erstmal kein Problem, im Cocoon ist ein LDAP-Transformator integriert, der mit XML beschriebene LDAP-Abfragen an den Server stellt und das Ergebnis wiederum als XML liefert. Nur beschränkt sich hier die Dokumentation des Cocoon einzig und allein darauf, wie das XML aufgebaut sein soll, was zur Abfrage dient. Also stöberte ich nach einigen Beispielen herum und gewann dabei mehrere Erkenntnisse…
- Die Daten der Authentifizierung werden in Form von XML gespeichert
- Diese Daten müssen einen bestimmten Aufbau haben, um akzeptiert zu werden
- Automatische Anmeldung geht nicht, denn auf die Umgebungsvariablen zurückzugreifen ist sinnlos. Was interessiert mich der Nutzername unter dem der Cocoon läuft? Ich will den Nutzernamen der Nutzers vor dem Browser!
Nach mehreren Anläufen und Versuchen unter Mithilfe unseres Admins hatte ich eine Abfrage fertig, die mir die entsprechenden Daten lieferte. Damit war das Problem erstmal gelöst. Ich konnte bestimmen, welche Abteilung sich anmelden darf und auf welche Seiten sie zugreifen darf. Aber damit hört es ja nicht auf…
Level 3: Im Zentrum der Maschinenwelt
Das Problem besteht ja nicht darin, nur eine Abteilung zuzulassen und die anderen auszusperren. Nein, unterschiedliche Abteilungen sollen auf verschiedene, ja sogar gleiche Seiten zugreifen können. Das Problem war: 1 Abteilung = 1 Authentifizierungshandler und 1 Webseite = 1 Authentifizierungshandler. Alles klar? Nö? Na dann… Ich kann den Zugriff auf eine Webseite nur mit einem Handler schützen. Dieser Handler überprüft die Nutzerdaten so, dass sie genau einem Kriterium entsprechen, in diesem Falle der Zugehörigkeit zur Abteilung. Also geht es nicht so einfach, zwei Handler auf eine geschützte Webseite zu bringen. Lösungsmöglichkeiten:
- Jeweils eine Pipeline pro Abteilung, aber mit unterschiedlichen Handlern (schlechte Idee, weil eine Unmenge an Code entsteht, der redundant ist)
- Für jede Mischungskombination von Abteilung einen neuen Authentifizierungshandler schreiben (ganz schlechte Idee, denn die Kombinationsmöglichkeiten wachsen mit n! [sprich: n Fakultät])
- Es gibt einen Handler, der nur prüft, ob die Abteilung auf die Intranetabfrage zugreifen darf. Mit den Nutzerdaten, die von der Authentifizierung als XML abgelegt sind, kann bestimmt werden, welchen Menüpunkt sie sehen dürfen und welchen nicht (Fantastische Lösung – das Menü baut sich dynamisch zusammen, je nach Login-Daten)
Die letzte Lösung klang nur zu schön. Seit Montag hab ich mich (neben anderen Sachen) damit herumgeärgert. Man suche im Netz: Eine Möglichkeit in einer eXtensible Server Page (XSP) das XML der Authentifizierung auszulesen (Die XSP gehört in der Pipeline in den Bereich der Datenerzeugung). Mit XSP kann man prima XML erzeugen und in der Transformation kann ich prima die Authentifizierungsdaten auslesen (Tja, leider zu spät), aber dazwischen – nichts! Bis heute Nachmittag… ich kämpfte mich schon durch die Javadoc’s des Cocoon, als ich plötzlich die Lösung fand. Zwar etwas unorthodox, aber es ging…
UserState ustate = ((UserState) <xsp:expr> <xsp-session:get-attribute name=
"org.apache.cocoon.webapps.authentication.components.
DefaultAuthenticationManager/UserStatus"/></xsp:expr>);
if (ustate.hasHandler())
{
UserHandler uhand = ustate.getHandler("handlername_as_defined_in_sitemap");
String username = uhand.getUserId();
...
}
Und wie drücke ich das am besten für Menschen verständlich aus? Man bekommt die Hauptspeise serviert und möchte aber schon wissen, was es als Nachspeise gibt. Die steht aber im Kühlschrank. Also guckt man, während die Hauptspeise serviert wird, durch die offene Küchentür und erkennt anhand der Sauerei in der Küche, was es als Nachtisch gibt. Deswegen müssen Programmierer immer so viel logisch denken – sonst gibt’s keinen Nachtisch
Au weia… ich muss gehen…
Murphy schlägt zu
Erstmal grimmig gucken… Am Wochenende wurde mir witzelnd die Frage gestellt, wann denn mal eine neue Ausgabe von “Besser programmieren für die Welt von morgen!” erscheint. Ziemlich sicher antwortete ich darauf, dass ich doch nun mittlerweile alle Bugs beseitigt hab und es wohl keine weiteren Ausgaben geben wird. Naja klar, solange bis man das nächste Mal auf Arbeit geht – Danke, Herr Murphy.
Kurze Schilderung des Problems: Ich muss einen Betrag aufteilen und durch interne Berechnungen und Rundungen kommt es zu einem Differenzbetrag zwischen dem aufzuteilenden Betrag und der Summe der Einzelbeträge. Und nun stolperte ich beim Durchsehen der Tests, dass statt einem Cent eine Differenz von 0 Cent ausgegeben wird. Ich schob die Schuld natürlich wieder auf die Konvertierungsroutine, denn eine fix reinprogrammierte Ausgabe zeigte mir auch einen Betrag von einem Cent an. Merkwürdigerweise konnte ich dort keinen Fehler finden. Gaukelt mir etwa der Rechner was vor? War die Differenz von einem Cent auch wirklich ein Cent? Also zog ich von dem Betrag den Wert von 0.01 ab und ließ mir das Ergebnis ausgeben. Vermutung war vollkommen korrekt, denn die 0.01 war in Wirklichkeit eine 0.009999999999998. Und damit rutschte sie in dieser Routine an der Rundung der Nachkommastellen vorbei.
if (0.01 > value && -0.01 < value);
else
{
value = ((0.0<(value*100.0))?(value*100.0+0.5):(value*100.0-0.5))/100.0;
// unterschiedliche Behandlung der Nachkommastellen
if (0.0 < (value*100.0))
nachkomma = ((long)((value-floor(value))*100.0))%100;
else
nachkomma = ((long)((value-ceil(value))*100.0))%100;
}
Käfer
Jeder Programmierer hatte schon mal einen – einen Bug. Aber das die Bugs auch noch in Kategorien eingeteilt werden, machte mit auch erst heute ein Kollege klar. Bei den Bugs unterscheidet man folgende:
Heisenbug
Nach der Heisenbergschen Unschärferelation benannter Bug, der verschwindet oder sein Verhalten verändert, wenn er untersucht wird. Prominentestes Beispiel ist, wenn man ein Programm in der Release-Version erstellt hat und dann wieder eine Debug-Version erstellt und der Fehler dann verschwindet.
Bohr Bug
Der Bohr-Bug verhält sich gegensätzlich zum Heisenbug. Genau wie das Bohrsche Atommodell ist dieser Bug komplett nachvollziehbar und verändert sein Verhalten nicht. Also der klassische Computerbug.
Schrödingbug
Der Schrödingbug ist ein ganz witziger Bug – nachempfunden nach Schrödingers Gedankenexperiment mit der Katze, die gleichzeitig tot und lebendig ist, bis jemand nachgesehen hat und somit den Zustand festlegt. Übertragen auf den Bug ist der Fehler im Programm solange bis jemand sich den Quellcode ansieht und den Fehler feststellt. Ab diesem Moment bricht das Programm an dieser Stelle ab und hört erst damit auf, wenn der Bug entfernt wurde. Ziemlich unwahrscheinlich…
Mandelbug
Nach dem Amerikaner Mandelbrot benannter Bug, dessen Auftreten nicht bestimmt werden kann, weil die Komplexität des Systems sehr hoch ist, sodass sein Auftreten chaotisch ist. Der Mandelbug wird häufig dem Heisenbug gleichgesetzt, meiner Erfahrung nach verteilt sich ein Mandelbug auf mehrere Heisen-, Schröding- und Bohr-Bugs.
Quelle: Wikipedia (engl.)
7|-|1Z 1z 1337
Heute bin ich wieder mal im totalen Nerdmodus. Ich muss ungefähr so ausgesehen haben, als ich nachfolgenden Block geschrieben hab.
virtual void operator() (void * pDestType)
{
// Aufruf
((*mpObject).*mFPt)(pDestType);
}
Dieses wunderschöne Stück ist Teil eines Functors. Es ermöglicht einer Klasse eine Funktion einer anderen Klasse aufzurufen, ohne die Instanz bzw. den Funktionsnamen zu kennen. Selbst den Parameter bekomme ich unerkannt durch.
Aber wie erkläre ich das jetzt einem Normalsterblichen? Am besten mit dem Blogbeispiel! Jemand schreibt einen Beitrag für seine Freunde und schickt ihn ab. Der Freund sieht jetzt “Private Blogbeiträge für mich (1)” und macht ihn auf. Was da drin steht und wie weit der Freund den Text liest, ist dabei völlig egal. Dem Freund steht es jetzt noch frei, ob er einen Kommentar hinerlässt oder nicht. Ist das jetzt verständlich? Ich hoffe doch.
Grundprinzipien der Softwareentwicklung
… mal ganz einfach erklärt. Zunächst die Abarbeitungsprinzipien:
- FIFO (First In, First Out): Zu vergleichen mit der Schlange im Supermarkt. Wer als erster kommt, wird auch als erster abkassiert. Alle die später kommen, müssen sich hinten anstellen.
- LIFO (Last In, First Out): Zu vergleichen mit der Einkaufstüte. Was du zuletzt einpackst, mußt du als erstes wieder auspacken, damit die Tüte leer wird. Beim Computer ist es dann auch so, wie im realen Leben – wenn die Tüte voll ist, geht nichts mehr rein, der allseits beliebte Stack Overflow.
- jetzt NEU: GIGO (Garbage In, Garbage Out): Du kaufst eine Salatgurke, eine Tüte Gummibärchen und ein Nudelholz und wunderst dich zuhause, warum du daraus kein gescheites Mittagessen zaubern kannst. Wenn dich deine Frau dann noch mit dem Nudelholz vermöbelt und du nicht ohnmächtig wirst, nennt man das robust.

