The blog of Stephan2018-10-02T15:52:03+00:00http://blog.stekoe.deStephanmail@stekoe.deSubjunctive Driven Management2018-10-02T00:00:00+00:00http://blog.stekoe.de/2018/10/02/subjunctive-driven-management<p>Die Kultur eines Unternehmens ist fundamental wichtig für die Stimmung und Arbeitsbereitschaft seiner Belegschaft.
Ist sie durch Druck und Angst geprägt, wird sich kaum ein Mitarbeiter finden, der sich traut, neue Wege einzuschlagen und aus der grauen Masse hervorzutreten.
Köpfe die hervorstechen können leichter abgeschlagen werden…</p>
<p>Dies führt zu Unzufriedenheit, Lustlosigkeit, fehlender Strebsamkeit und auch zu psychischen Krankheiten.
Man jagt nichts anderem mehr hinterherjagt als den eigenen Vorgaben.
Hierdurch wird eine Kultur von Einzelkämpfern geschaffen, die weder nach links noch nach rechts schauen und immer nur sich und die eigenen Ziele im Blick haben.
Was auf der Strecke bleibt ist Innovationskraft, Vordenkertum und Mitarbeitermotivation im Allgemeinen.
Doch gerade diese Punkte sind es, die einen Arbeitgeber von einem sehr guten Arbeitgeber unterscheiden.</p>
<p>In einer wie oben beschriebenen Unternehmenskultur ist der Wille einzelner Personen Veränderungen anzustoßen gering und es wird eine harte Aufgabe für das Unternehmen gute Mitarbeiter einzustellen bzw. diese zu halten.
Langfristig wird dies dann zu einem Problem, da nicht nur die Kultur defekt ist, sondern auch kein Mensch mehr da ist und bereit wäre etwas zu ändern.</p>
<p>Doch wie kann man diesem entgegenwirken und was sollte dabei beachtet werden?
Der erste Weg ist natürlich das persönliche Gespräch.
Doch ein solches Gespräch sollte nicht von oben herab, sondern auf Augenhöhe und vertraulich geführt werden, denn ist ein Mitarbeiter bereit dazu und nennt offen Punkte die er als negativ ansieht, macht er sich gleichzeitig auch angreifbar.
Es gehört Mut dazu sich zu erheben und Änderungen bewirken zu wollen.
Dieser Mut ist jedoch leicht zu ersticken, indem er niedergeschrien, überhört, missachtet oder gar mit Missbilligung getadelt wird.
Passiert dies oder passiert dies zu oft, wird der einst motivierte Mitarbeiter stumm, zieht sich zurück und tut nichts anderes mehr als das, was ihm “befohlen” wird - oder aber er verlässt das Unternehmen.
Wie also mit Mitarbeitern umgegangen wird die gerne etwas bewegen wollen ist oftmals wegweisend dafür, wie sich ein Mitarbeiter in Zukunft verhalten wird<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup>.
Im Umkehrschluss heißt dies jedoch in keinster Weise, dass alles was vorgetragen wird auch umgesetzt werden muss.
Doch es hat etwas mit <em>Wertschätzung</em> und <em>Respekt</em> zu tun, ob man zumindest angehört wird oder nicht.
So ist es völlig akzeptabel, wenn ein Thema diskutiert und anschließend verworfen wird, da man sich auf Augenhöhe begegnet und als Mitarbeiter und Mensch ernst genommen wird.
In den seltensten Fällen kommt es vermutlich vor, dass ein Mitarbeiter das “Aufbegehren” als Selbstzweck betreibt.
Viel näher liegt die Vermutung, dass er mit der aktuellen Situation unzufrieden oder gar überfordert ist und nach Veränderung oder Hilfe sucht.</p>
<p>In einem Artikel empfiehlt Marcus Blankenship sich mit jedem Mitarbeiter zusammenzusetzen und ihn zu fragen, ob er sich schlecht behandelt fühlt und ob er das Gefühl hat, das seine Vorschläge nicht gehört werden<sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup>.
Grundsätzlich ist dies ein guter Anfang, doch letzten Endes ist entscheidend, was aus den gewonnenen Informationen gemacht wird.
Werden sie angehört und anschließend ignoriert ist niemandem geholfen; vielmehr fühlen sich die Mitarbeiter noch weiter missverstanden, ignoriert oder bewusst übergangen.
Eine Lose-Lose Situation ist entstanden, da sehr viel Zeit und Geld in die Gespräche investiert wurden und die Mitarbeiter langfristig im Gefühl bestärkt werden, dass sich eh nichts ändern wird und alles bleibt wie es ist.</p>
<p>Es geht also nicht nur darum zuzuhören, sondern auch darum, auf das Gesagte zu reagieren und es zu verarbeiten.
Auch hier gilt wieder, dass nicht alles umgesetzt werden soll (und kann) was gefordert oder gesagt wird, vielmehr geht es darum, dass man als Mitarbeiter Gehör findet und sich ernstgenommen fühlt, weil über die vorgetragenen Themen gesprochen, diskutiert und ein Ergebnis gefunden wurde.
Weiter schreibt Blankenship, dass gute Teams selbstständig über die Unternehmenskultur reflektieren und in einer Retrospektive offen Probleme ansprechen<sup id="fnref:3"><a href="#fn:3" class="footnote">3</a></sup>.
Dies ist wiederum auch nur solange der Fall, bis sie so häufig durch Nichtstun des Managements enttäuscht werden, dass die Euphorie des Teams in “nit-picking” umschlägt.</p>
<p>Wie kann man aus diesem Teufelskreis herauskommen?
Man sollte damit aufhören ständig Sätze zu bilden wie “wir sollten mal…” oder “wir müssten mal…”.
Diese konjunktivierte Sprechweise ist häufig mit der begründeten Annahme verbunden, dass sowieso nichts passieren wird.
Sätze die so anfangen sind es fast nicht wert gesprochen zu werden, da sie im Sande verlaufen und keine Handlung nach sich ziehen.
Vielmehr müssen Aussagen konkreter gefasst werden: Nicht die Mitarbeiter vertrösten sondern handeln; natürlich nicht blind!
Klare Aussagen treffen und einen konkreten Weg aufzeigen, wie mit den vorgetragenen Sorgen oder Problemen umgegangen wird.
Und wenn die Umsetzung ein langwieriger Prozess ist, sollten auch hier die Mitarbeiter stetig informiert bleiben, damit sie nachvollziehen können, dass es länger dauert und auch warum es länger dauert.</p>
<p>Nur eine offene Kommunikationsstruktur die auf gegenseitigem Respekt, auf Augenhöhe und wertschätzend stattfindet ist ein gutes Fundament motivierte Mitarbeiter zu halten und auch einstellen zu können.
Jegliche andere Herangehensweise führt früher oder später zu einem Kollaps der Kultur und einer Gleichschaltung der Angestellten, die dann folglich im Gleichschritt jeden Tag im selben Trott unmotiviert utopischen Zielen hinterherrennen.</p>
<!-- footnotes -->
<div class="footnotes">
<ol>
<li id="fn:1">
<p><a href="https://hackernoon.com/why-your-programmers-just-want-to-code-36da9973388e">https://hackernoon.com/why-your-programmers-just-want-to-code-36da9973388e</a> <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
<li id="fn:2">
<p><a href="https://hackernoon.com/a-wake-up-call-for-tech-managers-d0415775efd0">https://hackernoon.com/a-wake-up-call-for-tech-managers-d0415775efd0</a> <a href="#fnref:2" class="reversefootnote">↩</a></p>
</li>
<li id="fn:3">
<p><a href="https://hackernoon.com/how-coders-can-improve-envioronment-74e5f88cbc9">https://hackernoon.com/how-coders-can-improve-envioronment-74e5f88cbc9</a> <a href="#fnref:3" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Angular CLI-Build in Spring Boot Maven-Lifecycle integrieren2018-03-25T00:00:00+00:00http://blog.stekoe.de/2018/03/25/spring-boot-angular<blockquote>
<p>Zu diesen Beitrag existiert ein <a href="https://github.com/SteKoe/spring-boot-angular/tree/1-initial-spring-boot-project">GitHub Repository</a>, welches die einzelnen Abschnitte als Tag gepflegt hat.</p>
</blockquote>
<p>Vor einiger Zeit habe ich mir vorgenommen eine Applikation in Angular zu entwickeln, die mit Hilfe von Spring Boot ausgeliefert wird.
Ziel der Übung war es die benötigten CLI Commands für <code class="highlighter-rouge">ng</code> in den Maven-Lifecycle<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup> so zu integrieren, dass beim Aufruf von <code class="highlighter-rouge">mvn clean package</code> eine Spring Boot Applikation herausfällt, die eine transpilierte, also mit <code class="highlighter-rouge">ng build --prod</code> gebaute SPA enthält.
In diesem Blogpost beschreibe ich das grundlegende Vorgehen und lege meine Überlegungen diesbezüglich offen und begründe auch einen Teil meiner Entscheidungen entsprechend.</p>
<h2 id="1-neues-spring-boot-web-projekt-anlegen">1. Neues Spring Boot Web Projekt anlegen</h2>
<p>Um ein neues Spring Boot Web Projekt zu erzeugen habe ich zum Spring Initializrs<sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup> gegriffen und mir ein Spring 2.0.0 Projekt generieren lassen.
Als <em>dependency</em> habe ich ausschließlich <code class="highlighter-rouge">Web</code> eingegeben und anschließend das resultierende ZIP-File als Basis verwendet.
Führt man auf diesem Projekt <code class="highlighter-rouge">mvn spring-boot:run</code> aus, wird die Spring Boot Applikation unter Port 8080 gestartet und kann im Browser aufgerufen werden.
Da bisher keine HTML-Seite hinterlegt wurde, wird eine vordefinierte Fehlerseite ausgegeben.</p>
<h2 id="2-erste-statische-inhalte-ausliefern">2. Erste statische Inhalte ausliefern</h2>
<p>Spring Boot Web erlaubt es auf verschiedenste Arten statischen Inhalt auszuliefern.
Der einfachste Weg ist es, unter <code class="highlighter-rouge">src/main/resources</code> einen Ordner anzulegen, der <code class="highlighter-rouge">static</code> heißt.
In diesem Ordner habe ich testweise eine HTML-Datei <code class="highlighter-rouge">index.html</code> angelegt, welche den Klassiker <code class="highlighter-rouge">Hello, World!</code> ausgibt.
Startet man die Applikation nun neu, wird die <code class="highlighter-rouge">index.html</code> automatisch von Spring Boot als Startseite ausgeliefert und entsprechend im Browser angezeigt.</p>
<p>Wirft man einen Blick in das <code class="highlighter-rouge">target</code> Verzeichnis des Projektes, findet sich die <code class="highlighter-rouge">index.html</code>-Datei unter <code class="highlighter-rouge">classes/static</code> wieder.
Wollen wir also eine Angular Applikation von Spring Boot ausliefern lassen, muss die App nach <code class="highlighter-rouge">classes/static</code> transpiliert werden.
Im Umkehrschluss heißt das aber auch, dass unsere Angular Sourcen nicht im Ordner <code class="highlighter-rouge">src/main/static</code> liegen sollten, da diese ansonsten untranspiliert in das JAR einfließen und sie es nur unnötig aufblähen.
Ich verwende daher den Ordner <code class="highlighter-rouge">src/main/webapp</code> als Basisordner, da dieser semantisch genau das ausdrückt, was die Angular App darstellt und dieser Ordner nach Maven-Konvention genau hierfür vorgesehen ist.</p>
<p><strong>Anmerkung:</strong> An dieser Stelle sei angemerkt, dass das <code class="highlighter-rouge">webapp</code>-Verzeichnis nur dann verwendet werden sollte, wenn das maven-war-plugin<sup id="fnref:3"><a href="#fn:3" class="footnote">3</a></sup> nicht verwendet wird, da dies sonst davon ausgeht, dass sich in dem <code class="highlighter-rouge">webapp</code>-Ordner eine JSP/Java-basierte Webapplikaton befindet und versucht diese zu kompilieren.</p>
<h2 id="3-erzeugen-eines-initialen-angular-cli-projekts">3. Erzeugen eines initialen Angular CLI-Projekts</h2>
<p>Nun da klar ist, dass sich die Angular App Sourcen im <code class="highlighter-rouge">src/main/webapp</code> Ordner befinden sollen, erzeuge ich entsprechend dort eine neue Angular App über die CLI <code class="highlighter-rouge">ng new webapp</code>.
In dem neu erzeugten Angular Projekt kann nun wie gewohnt mit der Entwicklung der SPA angefangen werden und diese auch separat vom Spring Boot Projekt entwickelt werden.</p>
<h2 id="4-ausliefern-der-angular-app">4. Ausliefern der Angular App</h2>
<p>Führt man den Befehl <code class="highlighter-rouge">mvn clean package</code> aus und schaut in das <code class="highlighter-rouge">target</code> Verzeichnis, sieht man, dass dort noch keine Spur der Angular App zu finden ist, da das <code class="highlighter-rouge">webapp</code>-Verzeichnis nicht wie das <code class="highlighter-rouge">static</code>-Verzeichnis automatisch im <code class="highlighter-rouge">target</code>-Ordner landet.
Ziel ist es also nun, die Angular App wie in Schritt 2 beschrieben in den Ordner <code class="highlighter-rouge">classes/static</code> zu transpilieren.
Hierfür reicht es aus in der <code class="highlighter-rouge">angular-cli.json</code> das Property <code class="highlighter-rouge">outDir</code> so anpassen, dass es auf das <code class="highlighter-rouge">target</code>-Verzeichnis zeigt: <code class="highlighter-rouge">../../../target/classes/static</code>.
Führt man nun <code class="highlighter-rouge">ng build</code> aus, wird die Angular App in das <code class="highlighter-rouge">static</code>-Verzeichnis geschrieben und nach einem Neustart der Spring Boot Applikation auch ausgeliefert.</p>
<h2 id="5-automatisieren-der-schritte">5. Automatisieren der Schritte</h2>
<p>Wenn man nun das Projekt ausschließlich mit Hilfe von Maven bauen will, muss natürlich auch das <code class="highlighter-rouge">ng build</code> Command in den Build-Lifecycle von Maven integriert werden.
Dies hat mehrere Vorteile:
Zum einen muss man als Entwickler nicht mehrere Befehle nacheinander ausführen (<code class="highlighter-rouge">mvn package && ng build && maven spring-boot:run</code>), zum anderen kann die Entwicklung beider Projekte transparent voneinander stattfinden.
Als Java Entwickler brauche ich mich nicht mit den Angular CLI-Befehlen auseinanderzusetzen, da ich meine gewohnten Maven-Befehle benutzen kann und völlig transparent im Hintergrund die Angular CLI-Befehle ausgeführt werden und als Angular Entwickler kann ich mich ausschließlich auf den Ordner <code class="highlighter-rouge">src/main/webapp</code> konzentrieren und hier meine Angular CLI wie gewohnt nutzen.</p>
<p>Im Hinblick auf die Buildpipeline des Projekts bietet es sich an, die Abhängigkeiten zu benötigten Tools wie Maven, Java, Node, npm und Angular-CLI so weit zu reduzieren wie möglich.
Statt also auf ein global installiertes Angular CLI zu bauen, verwende ich das unter den <code class="highlighter-rouge">node_modules</code> befindliche Angular CLI-Paket.
Mit Hilfe des Befehls <code class="highlighter-rouge">node node_modules/@angular/cli/bin/ng build --prod</code> erreiche ich dasselbe Ergebnis wie mit dem Befehl <code class="highlighter-rouge">ng build --prod</code> mit dem Unterschied, dass ich die Angular CLI im ersten Fall nicht vorher mit dem Befehl <code class="highlighter-rouge">npm install -g @angular/cli</code> habe installieren müssen.
Für Entwickler, die mit Node, npm oder Angular nicht sehr vertraut sind, wäre es mit diesem Ansatz nun völlig ausreichend Node.JS zu installieren, was genau wie Maven und Java sowieso benötigt würde - der Aufwand neue Tools zu lernen und die Rüstzeit entfallen bzw. werden hierdurch auf ein Minimum reduziert.</p>
<p>Nun bleibt noch die Frage, wann und wie diese Befehle auszuführen sind.</p>
<h3 id="welche-lifecycle-phasen-sollen-verwendet-werden">Welche Lifecycle-Phasen sollen verwendet werden?</h3>
<p>Nach Durchsicht des Maven-Lifecycles scheinen sich die Phasen <code class="highlighter-rouge">verify</code> und <code class="highlighter-rouge">compile</code> anzubieten.
Die Phase <code class="highlighter-rouge">verify</code> gewährlistet, dass das Projekt korrekt ist und alle erforderlichen Informationen und Abhängigkeiten vorhanden sind.
In dieser Phase kann also <code class="highlighter-rouge">npm install</code> eingebaut werden, damit bei fehlenden oder falschen Dependencies im Angular Projekt der Build gemäß des Prinzips “fail fast” frühzeitig abbricht.
Das Transpilieren der Angular App hingegen implementiere ich in die Phase <code class="highlighter-rouge">compile</code>, da hier auch die Java Klassen kompiliert werden (<code class="highlighter-rouge">compile the source code of the project</code>).</p>
<p><strong>Achtung:</strong> Wird mit dem spring-boot-plugin gearbeitet (bspw. <code class="highlighter-rouge">mvn spring-boot:run</code>), muss das <code class="highlighter-rouge">npm install</code> in eine Phase zwischen <code class="highlighter-rouge">generate-resources</code> und <code class="highlighter-rouge">compile</code> integriert werden, da das spring-boot-plugin nicht nochmal die Phase <code class="highlighter-rouge">verify</code> aufruft.
Im verlinkten GitHub Repository ist daher der <code class="highlighter-rouge">npm install</code>-Befehl in die Phase <code class="highlighter-rouge">generate-resources</code> eingebunden.</p>
<h3 id="wie-können-die-erforderlichen-befehle-zu-einer-bestimmten-phase-ausgeführt-werden">Wie können die erforderlichen Befehle zu einer bestimmten Phase ausgeführt werden?</h3>
<p>Um sich in den Maven-Build einzuhängen existiert für das Ausführen von Befehlen das Maven Plugin <code class="highlighter-rouge">exec-maven-plugin</code><sup id="fnref:4"><a href="#fn:4" class="footnote">4</a></sup>.
Über dieses Plugin werden <code class="highlighter-rouge">executions</code> definiert, welche zu einer konfigurierbaren <code class="highlighter-rouge">phase</code> in der Reihenfolge ausgeführt werden, wie sie in der <code class="highlighter-rouge">pom.xml</code> definiert sind.
Daher werden zwei <code class="highlighter-rouge">executions</code> definiert: <code class="highlighter-rouge">npm-install</code> und <code class="highlighter-rouge">ng-build</code>, welche entsprechend mit den Commands <code class="highlighter-rouge">npm install</code> bzw. <code class="highlighter-rouge">nb build --prod</code> konfiguriert werden.</p>
<script src="https://gist.github.com/e41efe09abeaf216841a8c887214a231.js?file=npm-install.pom.xml"> </script>
<script src="https://gist.github.com/e41efe09abeaf216841a8c887214a231.js?file=ng-build.pom.xml"> </script>
<p>Führt man nun, nachdem das <code class="highlighter-rouge">exec-maven-plugin</code> eingebunden und konfiguriert wurde, <code class="highlighter-rouge">mvn clean package</code> aus, erzeugt Maven ein JAR-File im <code class="highlighter-rouge">target</code>-Verzeichnis welches man mit Hilfe des Befehls <code class="highlighter-rouge">java -jar <filename>.jar</code> ausführen kann.
Durch die skizzierte Integration der Angular CLI in den Maven-Lifecycle erhalten wir eine Spring Boot Applikation die über einen integrierten Tomcat unsere Angular App ausliefert.
Der Buildlifecycle hierbei ist völlig transparent!</p>
<h2 id="6-noch-einen-schritt-weiter-tests">6. Noch einen Schritt weiter: Tests</h2>
<p>Zwar ist das eigentliche Ziel meines Vorhabens bereits erreicht, doch möchte ich nun auch noch ein weiteres Detail in den Buildlifecycle einbauen: Tests!
Angular erlaubt es Tests zu schreiben und mit Hilfe des Commands <code class="highlighter-rouge">ng test</code> auszuführen.
Wie in den vorherigen Schritten gezeigt ist es ein Leichtes diesen Aufruf auch noch einzubauen.
Maven bietet die dedizierte Phase <code class="highlighter-rouge">test</code> an, in welcher man <code class="highlighter-rouge">ng test -sr</code> implementiert habe.
Das Flat <code class="highlighter-rouge">-sr</code> steht für <code class="highlighter-rouge">single-run</code> und führt die Tests einmalig aus.</p>
<script src="https://gist.github.com/e41efe09abeaf216841a8c887214a231.js?file=ng-test.pom.xml"> </script>
<div class="footnotes">
<ol>
<li id="fn:1">
<p><a href="https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference">Maven Lifecycle</a> <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
<li id="fn:2">
<p><a href="https://start.spring.io">Spring Initializt</a> <a href="#fnref:2" class="reversefootnote">↩</a></p>
</li>
<li id="fn:3">
<p><a href="https://maven.apache.org/plugins/maven-war-plugin/usage.html">Maven War Plugin</a> <a href="#fnref:3" class="reversefootnote">↩</a></p>
</li>
<li id="fn:4">
<p><a href="http://www.mojohaus.org/exec-maven-plugin/">Maven Exec Plugin</a> <a href="#fnref:4" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
iOS 11 - Änderungen am UI / UX2017-09-24T00:00:00+00:00http://blog.stekoe.de/2017/09/24/iOS11<p>Ich habe nun seit ein paar Tagen das neue Betriebssystem - iOS 11 - für mein iPhone SE installiert und bin von einigen Änderungen überrascht (worden).
Durchaus schreibe ich mir auf die Fahne ein Faible für Usability und User Interface Design zu haben, weswegen ich mich immer wieder gerne von den großen
Softwareherstellern wie Microsoft und Apple inspirieren lasse.
Windows 10 hat mir nach Windows Vista das erste Mal wieder richtig gut gefallen, weil es von der Optik, aber auch Benutzerführung überzeugen konnte.
Der Vorgänger Windows 8 hingegen hat durch den artifiziellen Zwang, Tablet-Steuerung und -Oberflächen auf den PC zu bringen abgeschreckt.
Bei Apple ist natürlich auch nicht alles Gold was glänzt und hier findet in vielen Teilen eine Bevormundung des Nutzers statt, welche sich nicht von der Hand weisen lässt.
Nichtsdestotrotz möchte ich in diesem Artikel ganz unvoreingenommen über die mir sofort ins Auge gefallenen Veränderungen an iOS 11 eingehen und diese für mich einordnen.
Hierzu fangen wir ganz von vorne an: Am Sperrbildschirm.</p>
<h2 id="der-sperrbildschirm">Der Sperrbildschirm</h2>
<p>Der Sperrbildschirm ist der Einstiegspunkt in iOS.
Er ist fundamental wichtig, da hier der erste Eindruck überzeugen muss, um mich als Benutzer abzuholen.
Apple hat mit iOS 11 dem Einstiegspunkt ein kleines Facelifting verpasst, welches sich nicht nur in neuen UI-Elementen, sondern auch Transitionen niederschlägt.
Auffällig für mich war die veränderte Einblendung, wenn man das iPhone aus dem Sleepmodus holt.
Statt wie bisher wird nicht das Hintergrundbild komplett eingeblendet, sondern beginnend von unten links nach oben rechts.
Dies bringt verglichen zu iOS 10 eine neue, frische Dynamik auf den Sperrbildschirm, welcher sich im Vergleich angenehmer anfühlt als bisher.</p>
<h3 id="die-mitteilungszentrale">Die Mitteilungszentrale</h3>
<p>Will man die Mitteilungszentrale einsehen, so genügt nach wie vor ein Wischen von oben nach unten ober den Bildschirm.
In iOS 10 jedoch zog man durch diese Gestik die Mitteilungszentrale ebenfalls aus dem oberen Bildschirmrand über den gesamten Bildschirm nach unten.
Mit iOS 11 schiebt sich die Uhr- und Datumsanzeige nach oben und von unten werden die verpassten Mitteilungen eingeblendet.
Dies fühlt sich etwas unintuitiv an, da hier die Gestik (von oben nach unten) und die Bewegung der Elemente auf dem Bildschirm (von unten nach oben) gegeneinander wirken.
Erst wenn man auf dem Bildschirm nach oben wischt und dasselbe Ergebnis erhält, fühlt sich der Aufruf der Mitteilungen wieder nativ an.</p>
<h2 id="die-statusanzeige">Die Statusanzeige</h2>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2017-09-24-iOS11/statusbar.png" target="_blank" class="image ">
<img src="/assets/images/posts/2017-09-24-iOS11/statusbar.png" alt="Image" />
</a>
</figure>
<p>Auch die Statusanzeige wurde überarbeitet: So verschwinden die mit iOS 7 eingeführten Punkte als Empfangsstärkebalken des Mobilfunknetzes.
Ersetzt werden diese durch altbekannte Balken, welche auch bis iOS 6 verwendet wurden.
Hierdurch wird eine Menge Platz eingespart, welcher das Springen der Status-Icons unterbindet.
Dies war vor allem dann der Fall, wenn Bluetooth, Wecker, GPS, die prozentuale Ladeanzeige und VPN aktiviert waren, da hier dann der Platz doch sehr knapp waren.
Auch die Überarbeiteten Icons in der Statusanzeige runden das Gesamtbild ab.</p>
<h2 id="das-kontrollzentrum">Das Kontrollzentrum</h2>
<figure class="img-thumbnail float-right" style="width:140px">
<a href="/assets/images/posts/2017-09-24-iOS11/kontrollzentrum.png" target="_blank" class="image ">
<img src="/assets/images/posts/2017-09-24-iOS11/kontrollzentrum.png" alt="Image" />
</a>
</figure>
<p>Das neue Kontrollzentrum wurde deutlich reduziert.
An ihm scheiden sich auch die Geister, da die Darstellungsweise der verschiedenen Optionen stark geändert wurde.
Positiv finde ich, dass man nun die enthaltenen Elemente Anpassen und ordnen kann.
Auch dass man das Mobilfunknetz abschalten kann finde ich persönlich sehr gut.
Insgesamt fühlt sich das Kontrollzentrum aber auch besser an, da hier die Optionen nicht mehr über mehrere Seiten verteilt sind.
Alles in allem wurden die Elemente auf das Wesentliche reduziert und die Darstellung ist in meinen Augen der Funktionsweise entsprechend ausreichend gut.
Gewöhnungsbedürftig ist das neue Verhalten der Schalter für Bluetooth, WiFi und Mobilfunk.
Haben sie bisher die jeweilige Funktion abgeschaltet, werden seit iOS 11 nur noch die aktiven Verbindungen unterbrochen.
Die jeweiligen Funktechnologien hingegen bleiben aktiv.
Um diese komplett zu deaktivieren muss nun in den Systemeinstellungen der Schalter aktiv umgelegt werden.</p>
<h2 id="der-app-switcher">Der App Switcher</h2>
<figure class="img-thumbnail float-left" style="width:140px">
<a href="/assets/images/posts/2017-09-24-iOS11/appswitcher.png" target="_blank" class="image ">
<img src="/assets/images/posts/2017-09-24-iOS11/appswitcher.png" alt="Image" />
</a>
</figure>
<p>Eine weitere Veränderung hat der App Switcher erhalten.
Wir dieser Aufgerufen, bewegt sich der Home Screen in den Hintergrund und die geöffneten Apps rutschen von links in den Sichtbereich.
Insgesamt scheint auch diese Transition im Detail etwas überarbeitet worden zu sein.
Zwar lassen sich keine großen Unterschiede erkennen, aber der Eindruck ist verglichen zu iOS 10 leicht anders.
Der Home Screen selbst ist nicht mehr Bestandteil des App Switchers sondern kann durch das Drücken des Home Buttons oder das Tappen neben eine der offenen Apps aufgerufen werden.
Im Nachhinein ist die Entscheidung den Home Screen aus der Auflistung zu entfernen durchaus eine valide Lösung, da dieser für sich keine eigenständige App im engeren Sinne darstellt.
Andererseits bricht Apple an dieser Stelle gewohnte Wege, da hier ein Weg zur Rückkehr zum Home Screen entfällt.</p>
<h2 id="app-titel">App Titel</h2>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2017-09-24-iOS11/app-titles.png" target="_blank" class="image ">
<img src="/assets/images/posts/2017-09-24-iOS11/app-titles.png" alt="Image" />
</a>
</figure>
<p>Verwendet man die von Apple gestellten Apps wird eine neue Designlinie ersichtlich:
In vielen - bei weitem nicht allen - Apps setzt Apple auf der Einstiegsview auf eine große, abgesetzte Überschrift, die den Zweck des gezeigten Inhalts unterstreicht.
Durch die immer größer werdenden Bildschirme ist die Verwendung größerer Elemente durchaus in Ordnung.
Auf meinen kleinen iPhone SE Bildschirm schwindet der eigentliche Inhalt nun nach unten und ich muss vermehrt scrollen.</p>
<h2 id="fazit">Fazit</h2>
<p>Bisher gefallen mir die neuen Elemente in iOS 11 sehr gut.
Natürlich gibt es einige Stellen, an denen man noch nachbessern kann (vielleicht sogar muss), dennoch ist mir bisher keine Änderung aufgefallen, welche mich in der Verwendung des Telefons einschränken oder gar behindern.
Was jedoch deutlich auffällt sind einige UI-Flaws, also Bugs im UI-Design, welche eher untypisch für Apple sind.
So sind Suchfelder manchmal überdeckt, Texte überlappen sich und auch Überschriften scheinen nicht immer 1:1 an derselben Stelle zu stehen, wenn man die einzelnen Positionen App-übergreifend vergleicht.
Wie bei jedem Update gilt: Wenn nicht unbedingt nötig, muss man es nicht machen.
Auch wenn Software getestet wird bietet es sich an auf einer spätere Version des iOS 11 zu warten, damit die gröbsten Schnitzer beseitigt werden konnten.</p>
OCL.js2017-08-28T00:00:00+00:00http://blog.stekoe.de/2017/08/28/ocl.js<ol id="markdown-toc">
<li><a href="#einleitung" id="markdown-toc-einleitung">Einleitung</a> <ol>
<li><a href="#shortcomings-von-modellierungssprachen" id="markdown-toc-shortcomings-von-modellierungssprachen">Shortcomings von Modellierungssprachen</a></li>
<li><a href="#ocl-ftw" id="markdown-toc-ocl-ftw">OCL ftw!</a></li>
</ol>
</li>
<li><a href="#vom-string-zum-ast" id="markdown-toc-vom-string-zum-ast">Vom String zum AST</a> <ol>
<li><a href="#der-lexer" id="markdown-toc-der-lexer">Der Lexer</a></li>
<li><a href="#der-parser" id="markdown-toc-der-parser">Der Parser</a></li>
</ol>
</li>
<li><a href="#verwendung-der-ocljs" id="markdown-toc-verwendung-der-ocljs">Verwendung der OCL.js</a></li>
</ol>
<h2 id="einleitung">Einleitung</h2>
<p>Während meines Studiums der Wirtschaftsinformatik habe ich mich auf die Modellierung mit Hilfe von speziellen Sprachen spezialisiert.
Stets zentraler Augenmerk wurde auf den Aspekt <em>Abstraktion</em> gelegt, welchem alle Modellierungssprachen folgen.
Ethymologisch betrachtet kommt das Wort <em>Abstraktion</em> bzw. das entsprechende Verb <em>abstrahieren</em> aus dem lateinischen und bedeutet so viel wie <em>abziehen</em>, <em>entfernen</em> oder <em>trennen</em>.
Mit Hilfe von Modellierungssprachen <em>trennt</em> man sich von gewissen Dingen, nämlich von Details oder Aspekten, welche für den aktuell betrachteten Fall oder die Domäne nicht relevant sind.</p>
<h3 id="shortcomings-von-modellierungssprachen">Shortcomings von Modellierungssprachen</h3>
<p>Modellierungssprachen wie beispielsweise die UML haben jedoch einen zentralen Nachteil:
Die Ausdrucksmöglichkeiten sind begrenzt, sodass verschiedene Sachverhalte nicht durch die verwendete Sprache allein abgebildet werden können oder dies nur schwer möglich ist.</p>
<p>Das folgende Beispiel soll dies verdeutlichen.
Abbildung 1 zeigt ein UML-Diagramm, welches beschreibt, dass eine Person keine oder mehrere Autos besitzen kann.
Ein Auto hat immer nur genau einen Fahrzeughalter.</p>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2017-08-28-ocl.js/uml-example.png" target="_blank" class="image ">
<img src="/assets/images/posts/2017-08-28-ocl.js/uml-example.png" alt="Image" />
</a>
<figcaption class="figure-caption">Abb. 1: UML-Beispiel: Person besitzt Autos</figcaption>
</figure>
<p>Neben den Attributen der jeweiligen Objekten <code class="highlighter-rouge">Person</code> und <code class="highlighter-rouge">Auto</code> ist keinerlei weitere Semantik dem Diagramm zu entnehmen.
Wie aber ist vorzugehen, wenn nun die Bedingung, dass eine Person mindestens 18 Jahre alt sein muss um Autos zu besitzen, abzubilden ist?</p>
<h3 id="ocl-ftw">OCL ftw!</h3>
<p>An dieser Stelle greift die OCL.
Sie ergänzt die gegebene Modellierungssprache um weitere Konzepte, welche <em>Constraints</em> – also weitere Einschränkungen – abbilden können.</p>
<h5 class="no_toc" id="1-beispiel-der-besitzer-eines-autos-muss-älter-als-18-jahre-sein">1. Beispiel: Der Besitzer eines Autos muss älter als 18 Jahre sein</h5>
<p>Kommen wir zurück zu dem Beispiel, wo eine Person erst dann Autos besitzen darf, wenn diese über 18 Jahre alt ist.
Mit Hilfe der gegebenen Modellierungssprache ist diese Einschränkung nur schwer oder gar nicht umsetzbar, da für die Prüfung Instanzdaten benötigt werden, welche auf der abstrakten Modellebene noch nicht bekannt sind.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">context</span> <span class="no">Person</span>
<span class="ss">inv: </span><span class="nb">self</span><span class="p">.</span><span class="nf">age</span> <span class="o"><</span> <span class="mi">18</span> <span class="n">implies</span> <span class="nb">self</span><span class="p">.</span><span class="nf">fleet</span><span class="o">-></span><span class="n">size</span><span class="p">()</span> <span class="o">=</span> <span class="mi">0</span>
</code></pre></div></div>
<p>Die obige OCL-Regel legt eine Invariante für den <em>context</em> Person fest und bezieht sich somit auf alle Objekte des Typs <em>Person</em>.
Die Invariante legt fest, dass wenn eine Person jünger als 18 Jahre alt ist, die Fuhrparkgröße ebenfalls 0 sein muss.</p>
<h5 class="no_toc" id="2-beispiel-eine-person-kann-nicht-sein-eigenes-elternteil-sein">2. Beispiel: Eine Person kann nicht sein eigenes Elternteil sein</h5>
<p>Ein weiteres Beispiel stellt folgendes Diagram dar:</p>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2017-08-28-ocl.js/uml-example-2.png" target="_blank" class="image ">
<img src="/assets/images/posts/2017-08-28-ocl.js/uml-example-2.png" alt="Image" />
</a>
<figcaption class="figure-caption">Abb. 2: UML-Beispiel: Eine Person hat zwei Elternteile</figcaption>
</figure>
<p>Eine Person hat zwei Elternteile.
Was jedoch eine (biologische) Einschränkung darstellt ist, dass eine Person nicht sich selbst als Elternteil haben kann.
Es ist schwer - wenn nicht unmöglich - dies allein über die gegebenen Konzepte von UML zu lösen.
Mit Hilfe der folgenden, simplen OCL-Regel hingegen, wird die Einschränkung auf intuitive Weise festgehalten.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">context</span> <span class="no">Person</span>
<span class="ss">inv: </span><span class="nb">self</span><span class="p">.</span><span class="nf">parents</span><span class="o">-></span><span class="n">forAll</span><span class="p">(</span><span class="nb">p</span> <span class="o">|</span> <span class="nb">p</span> <span class="o"><></span> <span class="nb">self</span><span class="p">)</span>
</code></pre></div></div>
<p>Diese OCL-Regel definiert erneut eine Invariante für den <em>context</em> Person, welche prüft, dass für alle Elemente in der Collection <em>parents</em> gilt, dass diese nicht <em>self</em> (ich selbst) sind.</p>
<p>Obige Beispiele sollen zeigen, wie die OCL funktioniert und für welche Anwendungszwecke sie verwendet werden kann.
Im folgenden Abschnitt wird erklärt, wie die Implementierung der OCL.js strukturiert ist.</p>
<h2 id="vom-string-zum-ast">Vom String zum AST</h2>
<p>OCL ist eine textbasierte Sprache und muss daher zunächst von einem Text in eine ausführbare Form gebracht werden.
Dies erfolgt über die klassische Verkettung von Lexer und Parser, welche einen String zerlegen und aus den zerlegten Einzelteilen einen Abstract-Syntax-Tree<sup id="fnref:3"><a href="#fn:3" class="footnote">1</a></sup> (AST) erzeugen (s. Abbildung 3).</p>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2017-08-28-ocl.js/vom-string-zum-ast.png" target="_blank" class="image ">
<img src="/assets/images/posts/2017-08-28-ocl.js/vom-string-zum-ast.png" alt="Image" />
</a>
<figcaption class="figure-caption">Abb. 3: Vom String zum AST</figcaption>
</figure>
<h3 id="der-lexer">Der Lexer</h3>
<p>Ein Lexer übernimmt die Aufgabe die als Text eingegebene OCL-Regel in einzelne Token zu zerlegen.
Hierfür wird definiert, welche Teile des eingegebenen Strings in Token übersetzt werden.
Das folgende Listing zeigt einen Auszug aus der OCL.js Lexer-Definition.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>\s+ /* ignore whitespaces */
\-?[0-9][0-9]* return 'integer'
"context" return 'context'
"inv" return 'inv'
"->" return '->'
"(" return '('
")" return ')'
"." return '.'
":" return ':'
[a-zA-Z][a-zA-Z0-9]* return 'simpleName'
">" return '>'
</code></pre></div></div>
<p>Mit Hilfe der oben angeführten Lexer-Definition, kann folgende OCL-Regel in einzelne Token zerlegt werden.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">context</span> <span class="no">Car</span> <span class="ss">inv:
</span><span class="nb">self</span><span class="p">.</span><span class="nf">licensePlateNumber</span><span class="o">-></span><span class="n">size</span><span class="p">()</span> <span class="o">></span> <span class="mi">0</span>
</code></pre></div></div>
<p>Wurde die OCL-Regel in Token zerlegt, ergibt sich folgendes Bild:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>context simpleName inv:
simpleName.simpleName->simpleName() > integer
</code></pre></div></div>
<h3 id="der-parser">Der Parser</h3>
<p>Die Aufgabe des Parsers ist nun, die einzelnen Token gemäß einer gegebenen Grammatik in einen Abstract-Syntax-Tree zu wandeln.
Ein Auszug der OCL-Grammatik ist im folgenden Listing zu sehen.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>classifierContextDecl
: context simpleName inv
{ $$ = new ContextExpression($2, $3) }
;
inv
: inv simpleNameOptional : oclExpression
{ $$ = new InvariantExpression($4, $2) }
;
oclExpression
: pathName
{ $$ = new Expression.VariableExpression($1) }
| oclExpression . simpleName
{ $$ = new Expression.VariableExpression([$1.variable, $3])
| oclExpression -> simpleName
{ $$ = functionCallExpression($3, $$); }
;
</code></pre></div></div>
<p>Trifft eine der gegebenen Grammatikregeln auf die kombination der gegebenen Token zu, wird entsprechend eine Expression instanziiert.
Sind alle Token verarbeitet, ergibt sich ein AST, welches im folgenden Listing zu sehen ist.
Abbildung 4 zeigt den AST zudem in Form eines Baumdiagramms.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ContextExpression[name:”Car”]
- InvariantExpression[name:””]
- OperationCallExpression[operator:”>”]
- SizeExpression[name=”size”]
- VariableExpression[variable:“self.licensePlateNumber”]
- NumberExpression[number:”0”]
</code></pre></div></div>
<p>Die einzelnen Expressions / Bestandteile des AST folgem dem Interpreter-Pattern<sup id="fnref:4"><a href="#fn:4" class="footnote">2</a></sup> und implementieren jeweils eine <code class="highlighter-rouge">evaluate()</code>-Funktion.
Mit Hilfe dieser Funktion können die Invarianten gegen eine gegebene Menge an Objekte evaluiert werden.</p>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2017-08-28-ocl.js/ast.png" target="_blank" class="image ">
<img src="/assets/images/posts/2017-08-28-ocl.js/ast.png" alt="Image" />
</a>
<figcaption class="figure-caption">Abb. 4: Resultierender AST</figcaption>
</figure>
<h2 id="verwendung-der-ocljs">Verwendung der OCL.js</h2>
<p>Die Installation der OCL.js ist denkbar einfach:
Mit Hilfe des Package-Managers NPM lässt sie sich ganz einfach dem Projekt hinzufügen:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm install ocl.js
</code></pre></div></div>
<p>Anschließend lässt sich in einer JavaScript-Datei die ‘ocl.js’ importieren, welche eine <em>OclEngine</em> exportiert.
Die <em>OclEngine</em> stellt eine API bereit, welche <a href="https://ocl.stekoe.de/">hier</a> näher dokumentiert ist.
Über die Funktion <em>addOclExpression</em> lassen sich neue OCL-Regeln der Engine bekannt machen.
Anschließend kann der <em>evaluate</em>-Funktion ein Objekt übergeben werden, welches von der OCL-Engine geprüft wird.</p>
<p>Als Ergebnis erhält man ein <em>ResultObject</em>, welches das Ergebnis der Evaluation enthält (<em>true</em> oder <em>false</em>) sowie die Namen der fehlgeschlagenen Invarianten.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Import the OclEngine</span>
<span class="k">import</span> <span class="nx">OclEngine</span> <span class="k">from</span> <span class="s1">'ocl.js'</span><span class="p">;</span>
<span class="c1">// Create an instance of the OclEngine</span>
<span class="kd">const</span> <span class="nx">oclEngine</span> <span class="o">=</span> <span class="nx">OclEngine</span><span class="p">.</span><span class="nx">create</span><span class="p">();</span>
<span class="c1">// Define an OCL expression</span>
<span class="kd">const</span> <span class="nx">myOclExpression</span> <span class="o">=</span> <span class="s2">`
context Car inv:
self.licensePlateNumber->size() > 0
`</span><span class="p">;</span>
<span class="c1">// Add the expression to the engine and let the lexer / parser run</span>
<span class="nx">oclEngine</span><span class="p">.</span><span class="nx">addOclExpression</span><span class="p">(</span><span class="nx">myOclExpression</span><span class="p">);</span>
<span class="c1">// Pass in an object to evaluate against the given OCL expressions</span>
<span class="c1">// registered in the OclEngine instance.</span>
<span class="kd">const</span> <span class="nx">resultObj</span> <span class="o">=</span> <span class="nx">oclEngine</span><span class="p">.</span><span class="nx">evaluate</span><span class="p">({});</span>
<span class="c1">// Get the actual result of the evaluation (true / false)</span>
<span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">resultObj</span><span class="p">.</span><span class="nx">getResult</span><span class="p">();</span>
<span class="c1">// The names of failed invariants. May be "anonymous" if</span>
<span class="c1">// the invariant was not given a name.</span>
<span class="kd">const</span> <span class="nx">failedConstraints</span> <span class="o">=</span> <span class="nx">result</span><span class="p">.</span><span class="nx">getNamesOfFailedInvs</span><span class="p">();</span>
</code></pre></div></div>
<div class="footnotes">
<ol>
<li id="fn:3">
<p>https://de.wikipedia.org/wiki/Abstrakter_Syntaxbaum <a href="#fnref:3" class="reversefootnote">↩</a></p>
</li>
<li id="fn:4">
<p>https://de.wikipedia.org/wiki/Interpreter_(Entwurfsmuster) <a href="#fnref:4" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Jenkins CI - Integrationstests mit Docker2017-01-02T00:00:00+00:00http://blog.stekoe.de/2017/01/02/jenkins-ci-integrationstests-mit-docker<p>Jenkins ist eines der weltweit führenden Werkzeuge das sich auf Continuous Integration (CI) fokussiert. CI ist ein etabliertes Vorgehensmuster, welches Codeänderungen nachdem diese in ein Source-Code-Repository überspielt wurden automatisiert kompiliert und testet. Auch bei GBTEC werden verschiedene Instanzen von Jenkins CI eingesetzt, um den Source-Code unserer Produkte zu kompilieren und einer Qualitätskontrolle zu unterziehen. Um die Instanzen schnellstmöglich aufsetzen zu können, wird hierfür Docker verwendet. In einem entsprechenden Dockerfile werden die Jenkins-Version, benötigte Plugins sowie verschiedene Groovy-Scripts eingesetzt, um eine schnelle Installation einer neuen Jenkins-Instanz zu ermöglichen. In diesem Artikel wird vorgestellt, wie mit Hilfe von Jenkins und Docker Datenbanken für Integrationstests aufgesetzt und anschließend wieder entfernt werden.</p>
<!--more-->
<h2>Docker-Umgebung in Jenkins anmelden</h2>
<p>Um innerhalb von Jenkins Docker Container starten zu können, muss Jenkins Zugriff auf einen Docker-Host bekommen. Dies wird erreicht, indem sowohl der Docker-Socket, als auch die Docker-Executable beim Start des Jenkins Containers in diesem gemounted werden. Natürlich sind auch andere Möglichkeiten denkbar, wie beispielsweise das Einbinden einer externen Docker-Machine oder eines Amazon S3 Zugangs. Für unsere Zwecke ist das genannte Vorgehen jedoch ausreichend gut geeignet, um das angestrebte Ziel zu erreichen.</p>
<script src="https://gist.github.com/5891c56c387ae1260d3827811760f88d.js?file=run-docker.sh"> </script>
<p>Durch das Mounten des Sockets ist es nun möglich innerhalb von Jenkins mit Hilfe der Docker-CLI Befehle an den äußeren Docker-Host zu senden und neue Container zu starten bzw. zu stoppen.</p>
<h2>Verwendung von Datenbanken für Integrationstestzwecke</h2>
<p>Um Integrationstests laufen zu lassen, werden eine oder mehrere Instanzen verschiedener Datenbanktechnologien benötigt. Bisher wurden hierfür dedizierte virtuelle Maschinen im Netzwerk eingerichtet, auf denen jeweils eine Datenbank-Instanz läuft. Aus wirtschaftlicher Sicht ist dies ein verbesserungswürdiger Ansatz, da die Kapazitätsauslastung der einzelnen VMs moderat ist, da Integrationstests ausschließlich Nachts durchgeführt werden. Durch den Einsatz von Docker können Datenbank-Instanzen immer genau dann erzeugt werden, wenn diese benötigt werden und anschließend wieder entfernt werden. Durch das Entfernen der nicht mehr benötigten Instanzen können Ressourcen gespart und die Anzahl benötigter Host-Maschinen reduziert werden. Dies ist eine erhebliche Verbesserung gegenüber dem Einsatz nativer VM-Systeme, die permanent laufen oder als Image unnötig Speicherplatz belegen.</p>
<p>Für die Entwicklung der BIC Cloud werden bspw. die Datenbanken MySQL und OrientDB verwendet. Um Integrationstests gegen eine OrientDB laufen zu lassen, wird hierfür das offizielle Image aus dem Docker-Hub heruntergeladen und hochgefahren:</p>
<script src="https://gist.github.com/5891c56c387ae1260d3827811760f88d.js?file=run-orientdb.sh"> </script>
<p>Das Aufsetzen der benötigten Testdaten erfolgt autonom über die Integrationstestumgebung. Im Detail heißt dies, dass Integrationstests die benötigten Testdaten stets selbst definieren und keinen existierenden Datenbestand voraussetzen.</p>
<p>Sind die Tests durchgelaufen, wird über den Befehl <code>docker rm $JOB_NAME </code>die OrientDB-Docker-Instanz wieder entfernt. Durch die Verwendung einer Variable ist eine Kollision zwischen mehreren Jobs ausgeschlossen und es erlaubt parallel mehrere OrientDB-Instanzen zu starten. Durch das Entfernen der Instanz nach Durchführung der Tests wird der verwendete Plattenplatz wieder freigegeben und Seiteneffekte zwischen einzelnen Testdurchläufen verhindert.</p>
U2F - Universelle Zweifaktor-Authentifizierung2016-12-18T00:00:00+00:00http://blog.stekoe.de/2016/12/18/u2f-universelle-2fa<p>U2F ist ein von Google getriebener Standard, welcher unter dem Namen “FIDO” geführt wird. In Zusammenarbeit mit Yubico wurde die FIDO Alliance gegründet, welche fortan die Weiterentwicklung des FIDO-Standards übernimmt und überwacht. Kern dieses Standards ist ein USB-Dongle, welcher in Zusammenarbeit mit einer Software (bspw. Google Chrome) in der Lage ist eine Zweifaktor-Authentifizierung mittels eines Hardware-Dongles im Web zu realisieren. Einige Dienstleister bieten bereits die Möglichkeit an, den Login-Prozess mit Hilfe eines solchen USB-Dongles zusätzlich abzusichern. Neben den klassischen Verfahren wie One-Time-Passwords (OTP), welche ohne spezielle Soft- und Hardwarebindung auskommt, ist der Zugriff des Browsers auf das USB-Gerät für die U2F-Authentifizierung eine notwendige Voraussetzung und wird daher aktuell nicht von allen Browsern nativ unterstützt.</p>
<p>Um die in diesem Beitrag gezeigten Beispiele selbst ausprobieren zu können ist ein FIDO kompatibler Hardware-Dongle wie bspw. der “<a href="https://www.yubico.com/products/yubikey-hardware/yubikey4/">YubiKey</a>” notwendig. Zudem wird eine Node.JS-Umgebung in Version 4 benötigt. Aktuell ist der Zugriff auf den Dongle nur über Google Chrome ohne Zusatzsoftware möglich, sodass es sich anbietet, die Beispiele in diesem Browser auszuprobieren.</p>
<h2>Das Grundgerüst</h2>
<p>Bei dem entwickelten Beispiel handelt es sich um eine rudimentären Webseite, welcher mit Hilfe von Hapi.js auf Node.JS aufgesetzt wurde. Es existiert eine Login-Maske, ein interner Bereich, sowie eine Einstellungen-Seite und ein Logout. Die Einstelleungen-Seite erlaubt es dem Benutzer sein Zugang zusätzlich mit dem Yubikey zu schützen.</p>
<h3>Vorgehen</h3>
<p>Grundsätzlich ist zu beachten, dass die Verwendung von U2F nur funktioniert, sofern eine HTTPS-Verbindung zum Server vorliegt. Dies ist auch dann zu gewährleisten, wenn es sich um einen Test-Server handelt, der über <code>localhost</code> aufgerufen wird. Darüberhinaus ersetzt U2F nicht den klassische Loginansatz. Dieser ist weiterhin notwendig und auch Grundvoraussetzung für die Implementierung von U2F. Um U2F einsetzen zu können und Benutzern zu erlauben einen Dongle mit ihrem Benutzerkonto zu verknüpfen ist daher eine Benutzersession obligatorisch. Ferner werden sowohl im Frontend als auch im Backend entsprechende Bibliotheken benötigt, welche den FIDO-Standard implementieren. Yubico bietet hierfür ein JavaScript an, welches im Frontend eingebunden werden kann: <code>https://demo.yubico.com/js/u2f-api.js. </code> Für den Einsatz im Backend bietet sich die npm-Abhängigkeit <a href="https://www.npmjs.com/package/u2f">u2f</a> an, welche den serverseitigen Part implementiert.</p>
<h4>1. Registration Request</h4>
<p>Soll ein neuer Dongle registriert werden, muss der Server hierfür zunächst ein “registration request” stellen. Das folgende Gist zeigt, wie die Erzeugung eines “registration requests” aussieht (Zeile 2). Der Funktion <em>request(<appId>)</em> wird eine AppId übergeben, welche einem definierten Format folgen muss und auch mehrere “Facetten” abdecken kann.</p>
<blockquote>An (application) facet is how an application is implemented on various platforms. For example, the application PayPal may have an Android app, an iOS app, and a Web app. These are all facets of the PayPal application. (Quelle: <a href="https://developers.yubico.com/U2F/App_ID.html">Yubico</a>)</blockquote>
<p>Ist der “registration request” erstellt, wird dieser der Session angehängt, um den “request” zu einem späteren Zeitpunkt validieren zu können (Zeilen 6-16).</p>
<script src="https://gist.github.com/aec55b34e94bdde175399d31b9494a49.js?file=u2f.registration.request.js"> </script>
<h4>2. Registration Result</h4>
<p>Der vom Server erzeugte “registration request” wird an den Client übergeben. Er enthält eine Version, die AppId und eine Challenge. Diese Informationen müssen nun im Frontend in die u2f-Library übergeben werden:</p>
<script src="https://gist.github.com/aec55b34e94bdde175399d31b9494a49.js?file=u2f.process-request.js"> </script>
<p>Der Browser spricht nun den Dongle an und aktiviert diesen. Um der Anfrage zuzustimmen muss der Benutzer aktiv einen Knopf auf dem Dongle drücken, um so seine Zustimmung zum Pairing des Dongles mit der Anfrage zu geben. Tut der Benutzer dies nicht, wird ein Fehler geworfen, welcher mit dem Error-Code 5 angibt, dass die Benutzerinteraktion zu lange gedauert hat und ein erneuter “registration request” angefordert werden muss.</p>
<p>Gibt der Benutzer jedoch seine Zustimmung, wird eine Antwort auf die gegebene “Challenge” erstellt, die anschließend wieder an den Server gesendet werden muss.</p>
<h4>3. Registration Verification</h4>
<p>Mit Hilfe des vom Client zurück an den Server gesendeten Payloads kann nun überprüft werden, ob ein Pairing des Dongles mit dem Benutzerkonto erlaubt ist. Hierfür wird zunächst der “registration request” aus der Session ausgelesen und der u2f Bibliothek zusammen mit dem vom Client erzeugten Payload übergeben. Passen die Antwort vom Client zu dem in der Session gehaltenen “registration request” zusammen, wird ein öffentlicher Schlüssel, der den Dongle des Benutzers identifizieren kann, sowie ein <em>keyHandle</em> am Benutzer in der Datenbank abgelegt. Ab sofort kann mit Hilfe des öffentlichen Schlüssels geprüft werden, ob die von einem Dongle gesendete Signatur zu dem entsprechenden Benutzer passt.</p>
<script src="https://gist.github.com/aec55b34e94bdde175399d31b9494a49.js?file=u2f.handle.post.js"> </script>
<h4>4. Login Request</h4>
<p>Hat ein Benutzer einen FIDO-Dongle in seinem Benutzeraccount hinterlegt, muss die Login-Logik erweitert werden. Bisher war es ausreichend den Zugriff auf den internen Bereich direkt nach Eingabe der korrekten Kombination aus Benutzername und Passwort zu gewähren. Ist jedoch ein öffentlicher Schlüssel eines Benutzers hinterlegt, muss nach Eingabe der korrekten Benutzerdaten eine weitere Abfrage erfolgen, die den User auffordert den Dongle an den Computer anzuschließen und dem Login-Versuch durch drücken des Knopfes zuzustimmen.</p>
<p>Ähnlich wie bei der Registrierung eines Dongles (vgl. 1. Registration Request), muss vom Server eine Challenge angefordert werden, die auf den Daten des gespeicherten Dongles basiert. Hierfür wird auf Basis des gespeicherten <em>keyHandles</em> ein Sign-Request erstellt, welcher an den Client geschickt wird.</p>
<script src="https://gist.github.com/aec55b34e94bdde175399d31b9494a49.js?file=u2f.login.request.js"> </script>
<h4>5. Sign Request</h4>
<p>Nachdem der Sign-Request vom Server an den Client geschickt wurde, muss dieser durch den Benutzer bestätigt werden. Dies erfolgt über folgenden Code:</p>
<script src="https://gist.github.com/aec55b34e94bdde175399d31b9494a49.js?file=u2f.ui.login.request.js"> </script>
<p>Der vom Server gesendete <em>authRequest</em> wird der <em>sign(<…>)</em> Funktion übergeben und das Ergebnis zurück an den Server gesandt. Dieser muss nun prüfen, ob die erzeugte Antwort valide ist.</p>
<h4>6. Verify Login</h4>
<p>Die vom Client geschickte Antwort wird nun mit dem gestellten “login request” aus Schritt 4. sowie dem öffentlichen Schlüssel des Benutzers verifiziert. Werden vom u2f-Algorithmus keine Probleme festgestellt, wird die Session des Benutzers so initialisiert, dass der Zugriff auf die internen Seiten gewährt wird.</p>
<script src="https://gist.github.com/aec55b34e94bdde175399d31b9494a49.js?file=u2f.login.verification.js"> </script>
<h2>Pitfalls</h2>
<p>Während der Entwicklung der Beispielapplikation bin ich auf mehrere Fehler gestoßen, welche sich durch das Lesen der Dokumentation leider nicht lösen ließen und daher hier dokumentiert sind.</p>
<h4>"Unknown or missing requestId in response."</h4>
<p>Das Ergebnis der Recherche zeigt, dass hier entgegen der im Netz kursierenden Anleitungen die u2f-client-API falsch verwendet wird. Im Falle der Beispielapplikation sah der Code zunächst wie folgt aus:</p>
<pre>u2f.register([req], [], cb);</pre>
<p>Dem Aufruf der Funktion register jedoch muss die AppId als erster Parameter übergeben werden. Der korrekt funktionierende Aufruf gestaltet sich daher wie folgt:</p>
<pre>u2f.register(req<strong>.appId</strong>, [req], [], cb);</pre>
<h4>"Error Code: 2"</h4>
<p>Der Dokumentation ist zu entnehmen, dass bei einem Error Code 2 die AppId oder der Request falsch strukturiert sind. Zunächst ist auch hier wiederum darauf zu achten, dass die Funktion <code>u2f.register</code> korrekt verwendet wird. Besondere Beachtung gilt dem zweiten Parameter, welcher als Array übergeben werden muss. Ferner ist die AppId korrekt zu wählen: Zum einen ist es zwingend erforderlich, dass der Server über SSL, also HTTPS verfügt und die AppId entsprechend gestaltet wird: https://localhost. Ein Slash am Ende der URL führt ebenfalls zu ungewollten Seiteneffekten und Fehlern.</p>
Spotlight: Git rebase2016-02-21T00:00:00+00:00http://blog.stekoe.de/2016/02/21/spotlight-git-rebase<p>This article is about the common problem one faces, when working with feature branches.
At one point in time one wants to reintegrate a feature (branch) back into the current development branch (often called <em>master</em> or <em>development</em>).
Git offers two different approaches for this:
The simplest one is a <code class="highlighter-rouge">git merge</code> which creates a new commit containing the complete diff of the two branches.
The other but more complex one is a combination of <code class="highlighter-rouge">git rebase</code> and <code class="highlighter-rouge">git merge</code>.
These two commands in combination allows a user to merge not just only the file diffs but also preserves the complete history of the feature branch which may be helpful in most cases since the commit messages contain relevant information as well.</p>
<!-- more -->
<p>In order to set up a Git repository having two branches and some commits I have created a small bash script which creates some files and commits to the different branches.
Using this setup I have played around using <code class="highlighter-rouge">git rebase</code> command to illustrate how this command actually works. Figure 1 shows the commit graph which is the result when one executes the bash script.</p>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2016-02-21-spotlight-git-rebase/initial-repo-structure.svg" target="_blank" class="image ">
<img src="/assets/images/posts/2016-02-21-spotlight-git-rebase/initial-repo-structure.svg" alt="Image" />
</a>
<figcaption class="figure-caption">Fig. 1: Initial commit history of demo repository</figcaption>
</figure>
<p>At this point we assume that the feature is fully implemented and is about to be reintegrated into the master branch.
The question now is: How does one have to call the <code class="highlighter-rouge">git rebase</code> command.
Figure 2 and Figure 3 show the different results depending on which branch the <code class="highlighter-rouge">rebase</code> command is applied.
When the <code class="highlighter-rouge">rebase</code> command is called, Git looks for a common ancestor in the commit graph and uses this as basis for merging all later commits.
In this example <em>M2</em> is the last common commit of both branches and will be used as starting point.
Now one has to know how <code class="highlighter-rouge">rebase</code> actually works:
<code class="highlighter-rouge">git rebase</code> always appends all commits of a branch to the end of commits of the branch which is currently checked out.
Hence, when one wants to reintegrate a feature branch, one has to checkout the feature branch first and then call <code class="highlighter-rouge">git rebase master</code>.
When I call the <code class="highlighter-rouge">rebase</code> command I add an imaginary “<em>to</em>” to the call: <code class="highlighter-rouge">git rebase (to master)</code> which makes the way <code class="highlighter-rouge">rebase</code> is working clearer.
The command tells Git onto which branch the current branch shall be applied (cf. Figure 3).</p>
<h2 id="git-rebase-feature">git rebase feature</h2>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2016-02-21-spotlight-git-rebase/git-rebase-feature.svg" target="_blank" class="image ">
<img src="/assets/images/posts/2016-02-21-spotlight-git-rebase/git-rebase-feature.svg" alt="Image" />
</a>
<figcaption class="figure-caption">Fig. 2: Rebase feature branch (to master)</figcaption>
</figure>
<p>This example assumes, that the master branch is checked out.
Hence, the commits after <em>M2</em> are cut off and appended one by one to the very last commit of the feature branch.</p>
<h2 id="git-rebase-master">git rebase master</h2>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2016-02-21-spotlight-git-rebase/git-rebase-master.svg" target="_blank" class="image ">
<img src="/assets/images/posts/2016-02-21-spotlight-git-rebase/git-rebase-master.svg" alt="Image" />
</a>
<figcaption class="figure-caption">Fig. 3: Rebase master branch (to feature)</figcaption>
</figure>
<p>In this example we assume, that the feature branch is checked out.
Thus, the commits of the feature branch made after <em>M2</em> are cut off and appended one after the other to the last commit of the master branch.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Git’s <code class="highlighter-rouge">rebase</code> command is a nice way to preserve commits of a feature branch and allows to add all commits to the development branch without loosing them.
This helps to reduce the amount of branches as rebased branches can be safely removed.
But using <code class="highlighter-rouge">rebase</code> might also mess up your history, since the whole history (at least the timestamps) are reset.
Thus, <code class="highlighter-rouge">rebase</code> is dangerous as well when used the wrong way.</p>
<p>Nevertheless, using <code class="highlighter-rouge">rebase</code> over <code class="highlighter-rouge">merge</code> (espacially a fast-forward merge) always depends on the current use-case.
In some cases it might be useful to preserve the branch commit history, then one should rely on <code class="highlighter-rouge">rebase</code>.
When the history is irrelevant or contains messages which should not be part of the later result, using <code class="highlighter-rouge">git merge</code> might be a better choice.</p>
<h2 id="appendix-bash-script">Appendix: Bash script</h2>
<script src="https://gist.github.com/26e291331eb5eabb145b.js"> </script>
Spotlight: Git objects2016-02-17T00:00:00+00:00http://blog.stekoe.de/2016/02/17/spotlight-git-objects<ol id="markdown-toc">
<li><a href="#how-does-git-handle-contents" id="markdown-toc-how-does-git-handle-contents">How does Git handle contents?</a> <ol>
<li><a href="#blob-object" id="markdown-toc-blob-object"><abbr title="Binary Large Object">Blob</abbr> object</a></li>
<li><a href="#tree-objects" id="markdown-toc-tree-objects">Tree objects</a></li>
<li><a href="#commit-object" id="markdown-toc-commit-object">Commit object</a></li>
</ol>
</li>
<li><a href="#conclusion" id="markdown-toc-conclusion">Conclusion</a></li>
<li><a href="#appendix" id="markdown-toc-appendix">Appendix</a></li>
</ol>
<p>Have you ever wondered how Git handles files and folders in the magical <code class="highlighter-rouge">.git</code> folder?
Well, I did and hence I started to investigate further.
In this article I will present the results and explain the way how Git objects are interconnected.</p>
<p>Git<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup> is a source code management (<abbr title="Source Code Management">SCM</abbr>) system invented back in 2005 by Linus Torvalds, founder and inventor of Linux Kernel<sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup>.
His intention was to implement a distributed <abbr title="Source Code Management">SCM</abbr> system which supports common development workflows more easily compared to other SCMs like <abbr title="Apache Subversion">SVN</abbr>.
This includes that commits can be made locally without having the need of a remote repository or server.
In addition, compared to <abbr title="Apache Subversion">SVN</abbr> which uses incremented revision numbers, Git has to rely on some other techniques since there may occur revision collisions when merging local and remote changes, otherwise.
Hence Git introduces hashes using <abbr title="Secure Hash Algorithm">SHA1</abbr><sup id="fnref:3"><a href="#fn:3" class="footnote">3</a></sup> for each and every resource which is tracked.
The reason for using <abbr title="Secure Hash Algorithm">SHA1</abbr> is simple, as it is a fast but reliable algorithm to calculate hashes for a given input.
Although it is not very secure—it should not be used for hashing passwords anymore due to collision attacks—it is sufficient for the purpose of tracking file contents as Git does.</p>
<h2 id="how-does-git-handle-contents">How does Git handle contents?</h2>
<p>Git relies on the filesystem of the underlying operating system.
A filesystem basically has two different concepts: Files and folders.
Although Git does not track folders but files, there are two corresponding abstractions in Git’s source code: Tree and <abbr title="Binary Large Object">Blob</abbr>.
A <abbr title="Binary Large Object">Blob</abbr> contains the value of a file whereas a Tree is the pendant to a folder by listing all contained Blobs.</p>
<h3 id="blob-object"><abbr title="Binary Large Object">Blob</abbr> object</h3>
<p>Let’s assume that we have a file called <code class="highlighter-rouge">test.txt</code> which contains a simple, but well-known string: <code class="highlighter-rouge">Hello, World!</code>.
I already wrote, that Git tracks files by its contents using a <abbr title="Secure Hash Algorithm">SHA1</abbr> hash.
When hashing the string above one will get <code class="highlighter-rouge">60fde9c2310b0d4cad4dab8d126b04387efba289</code> as value.</p>
<p>Let’s verify whether Git calculates the same hash value by creating a new Git repository, add the file and inspect the <code class="highlighter-rouge">.git/objects/</code> folder:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git init <span class="nb">.</span>
<span class="nv">$ </span><span class="nb">echo</span> <span class="nt">-n</span> Hello, World! <span class="o">></span> test.txt
<span class="nv">$ </span>git add <span class="nb">.</span>
</code></pre></div></div>
<p>The <code class="highlighter-rouge">.git/objects/</code> folder now contains one new folder having one file:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.git
`-- objects
+-- b4
| `-- 5ef6fec89518d314f546fd6c3025367b721684
+-- info
`-- pack
</code></pre></div></div>
<p>The file and folder names are obviously hashed values of something.
In order to investigate the contents of a file, one can use the command <code class="highlighter-rouge">git cat-file -p b45e</code> which prints out:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git cat-file <span class="nt">-p</span> b45e
Hello, World!
</code></pre></div></div>
<p>Wait, what?! Why does the file has a hash value of <code class="highlighter-rouge">b4/5ef6fec89518d314f546fd6c3025367b721684</code>?
We did calculate some different hash value which is <code class="highlighter-rouge">60fde9c2310b0d4cad4dab8d126b04387efba289</code>, didn’t we?
Well, yes, we did, but Git tracks a little bit more information than just the plain content of a file:
It also respects the file size as well as the type of Git object that is tracked.
In this case the file has a size of 13 byte and is of type <em><abbr title="Binary Large Object">Blob</abbr></em>.
These information and the content of the file are taken, put into a new object and then hashed:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>blob 13\0Hello, World!
</code></pre></div></div>
<p>The format for Blobs is specified as follows: <code class="highlighter-rouge">blob<blank><filesize in byte><null byte><file content></code>.
The null byte is used to separate the content of a file from the git specific header which contains meta data.
If we hash the resulting string above once more, <abbr title="Secure Hash Algorithm">SHA1</abbr> returns <code class="highlighter-rouge">b45ef6fec89518d314f546fd6c3025367b721684</code>.
Looks familiar, right? Yes, it is the very same hash as generated by Git!</p>
<p>We are done, aren’t we? But wait… What about folders?
Until now, Git has tracked the file and its content, so we will have a look at folders now.</p>
<h3 id="tree-objects">Tree objects</h3>
<p>Since we are very happy having a mature <code class="highlighter-rouge">test.txt</code> file now, let’s first commit that and than investigate further.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git commit <span class="nt">-m</span> <span class="s2">"Initial commit."</span>
</code></pre></div></div>
<p>Let’s check the <code class="highlighter-rouge">.git/objects/</code> folder once more.
We will see that a new file has been created by Git with a hash value of <code class="highlighter-rouge">34/1cf04522a24fcf326c5e46ff7ce4f66ff310dd</code>.
In order to look inside that file, we can again use the <code class="highlighter-rouge">git cat-file</code> command as shown below.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.git
`-- objects
+-- b4
| |-- 5ef6fec89518d314f546fd6c3025367b721684
| `-- 587014507e76d7dcf5b5299949fae0b12b06ab
+-- 34
| `-- 1cf04522a24fcf326c5e46ff7ce4f66ff310dd
+-- info
`-- pack
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git cat-file <span class="nt">-p</span> 341c
100644 blob b45ef6fec89518d314f546fd6c3025367b721684 test.txt
</code></pre></div></div>
<p>The content is part of a Git <em>tree</em> object which is the way Git tracks folders and contents.
Some of you might know, that Git won’t track empty folders.
This is because a tree object has to have at least one element inside, which is false when no files are contained in a folder.</p>
<h3 id="commit-object">Commit object</h3>
<p>There is another new file which hasn’t been investigated, yet, having a hash value <code class="highlighter-rouge">b4/587014507e76d7dcf5b5299949fae0b12b06ab</code>.
Once again we can use the magic git command to look inside the file.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git cat-file <span class="nt">-p</span> b458
tree 341cf04522a24fcf326c5e46ff7ce4f66ff310dd
author Stephan Köninger <github@stekoe.de> 1455660483 +0100
committer Stephan Köninger <github@stekoe.de> 1455660483 +0100
Initial commit.
</code></pre></div></div>
<p>This object obviously contains the message we entered when committing the <code class="highlighter-rouge">test.txt</code> file.
Hence we can assume that this is the object which contains all information necessary for a commit.
The first line of the commit object points to the tree object we have seen in the previous chapter.
If one draws the different objects as a graph the result will look like as follows.</p>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2016-02-17-spotlight-git-objects/git-object-tree.svg" target="_blank" class="image ">
<img src="/assets/images/posts/2016-02-17-spotlight-git-objects/git-object-tree.svg" alt="Image" />
</a>
<figcaption class="figure-caption">Fig.1: Simple Git object tree</figcaption>
</figure>
<p>A more complex graph can be seen in the next figure which depicts two commits.
The second commit points back to its previous commit using a parent-child association.
As can be seen in the picture as well, the second commit introduces a new subfolder containing one file.
This assumes, that a tree object can not just contain blobs but tree objects as well.</p>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2016-02-17-spotlight-git-objects/more-complex-git-object-graph.svg" target="_blank" class="image ">
<img src="/assets/images/posts/2016-02-17-spotlight-git-objects/more-complex-git-object-graph.svg" alt="Image" />
</a>
<figcaption class="figure-caption">Fig.2: Extended Git object tree</figcaption>
</figure>
<h2 id="conclusion">Conclusion</h2>
<p>In this blog post I have shown the main objects which are used by Git to track changes, files and their folders.
We have also learned that Git uses hashes for revision numbers as well as tracing the object’s content.
In order to illustrate the way git calculates hashes, I have implemented the algorithm using JavaScript.
The resulting code can be found in the appendix of this blog post.</p>
<h2 id="appendix">Appendix</h2>
<script src="https://gist.github.com/SteKoe/20462841fa2b47ef6bcc.js"> </script>
<!-- footnotes -->
<!-- abbreviations -->
<div class="footnotes">
<ol>
<li id="fn:1">
<p><a href="https://git-scm.com">https://git-scm.com</a> <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
<li id="fn:2">
<p><a href="https://www.kernel.org">https://www.kernel.org</a> <a href="#fnref:2" class="reversefootnote">↩</a></p>
</li>
<li id="fn:3">
<p><a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">https://en.wikipedia.org/wiki/Secure_Hash_Algorithm</a> <a href="#fnref:3" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Spotlight: Git index2015-10-17T00:00:00+00:00http://blog.stekoe.de/2015/10/17/spotlight-git-index<p>I cannot remember when I started to use version control systems (VCS), but I know that I started by using Apache’s SVN. Nowadays the tool Git has gained more attention and is used in many companies as well as in software engineering in general. But even though I am using Git on a daily basis, I have not understood the main concepts of Git in detail yet. Therefore I will have a closer look on Git’s index and its behavior in this blogpost. I also plan to add more blogposts focussing on Git objects and the objects store.</p>
<!-- more -->
<p>Since Git is a very complex tool – it is a distributed system –, I will just focus on one local Git repository at the moment. Hence, this blogpost will not handle things like bare repositories or remote repositories at all. In order to understand the concept of Git’s index I write down all steps I have done to understand the way Git is working. The following list shows each step I have performed to see what kind of information is stored in the index.</p>
<h2 id="file-handling">File handling</h2>
<p><strong>Create a new empty Git repository</strong><br />
First of all I need to create an empty Git repository anywhere on my hard disc drive. In order to do so, I use the well known git command as follows:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git init <span class="nb">.</span>
Initialized empty Git repository <span class="k">in</span> ~/Development/spotlight-git-index
</code></pre></div></div>
<p><strong>Create new file: test.txt</strong><br />
Then I create a new file with some example content in it:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">echo</span> <span class="s2">"Test"</span> <span class="o">></span> test.txt
</code></pre></div></div>
<p><strong>Check Git’s index</strong><br />
Event though the new file has been created in the workspace, Git does not know the file yet. In order to link the file to Git, we have to add it as described in the following step.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git ls-files <span class="nt">--stage</span>
</code></pre></div></div>
<p><strong>Add file to Git’s index</strong><br />
In order to add the file to the Git index, one has to use the following command. After the command has been executed Git now knows the file and tracks it.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git add <span class="nb">.</span>
</code></pre></div></div>
<p><strong>Check Git’s index</strong><br />
When one checks Git’s index once again, one can see that Git knows the file and tracks it now. This is done by calculating an hash value of the file’s content which is added to the index and can be seen in the output of the index listing command.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git ls-files <span class="nt">--stage</span>
100644 345e6aef713208c8d50cdea23b85e6ad831f0449 0 test.txt
</code></pre></div></div>
<p><strong>Add another line to test.txt</strong><br />
In this step we are going to update the existing file by adding a new line of text.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">echo</span> <span class="s2">"Test"</span> <span class="o">>></span> test.txt
</code></pre></div></div>
<p><strong>Check Git’ index</strong><br />
When checking the index again, one can see that the index has not recognized the changes yet, since we have to tell Git to do so as described in the following step. Notice that the hash value has not yet changed in the output of the index listing command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git ls-files <span class="nt">--stage</span>
100644 345e6aef713208c8d50cdea23b85e6ad831f0449 0 test.txt
</code></pre></div></div>
<p><strong>Add modified test.txt file to index again</strong><br />
We now add the updated test.txt file to Git’s index again.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git add <span class="nb">.</span>
</code></pre></div></div>
<p><strong>Check Git’s index</strong><br />
The file test.txt has changed due to content modificiations and hence the hash value has changed as well. You can now see the newly generated hash value based on the new content of the file below.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git ls-files <span class="nt">--stage</span>
100644 95306f63471907a92e280462cdc96272bdd7b11b 0 test.txt
</code></pre></div></div>
<h2 id="folder-handling">Folder handling</h2>
<p><strong>Add a new folder</strong><br />
Let’s have a look how Git handles folders in the index. So let’s create an empty folder and add the changes to the index.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>mkdir folder
<span class="nv">$ </span>git add <span class="nb">.</span>
</code></pre></div></div>
<p><strong>Check Git’s index</strong><br />
When one now checks the index again, one can see that the empty folder is not recognized at all. This is due to Git’s focus on files only. Hence it is not even possible to commit empty folders. (<em>Note: One workaround to commit empty folders is to add a file named “empty” to it which indicates the users that the folder is somehow required in the project, and that the empty file is necessary to Git for commiting an empty folder</em>).</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git ls-files <span class="nt">--stage</span>
100644 95306f63471907a92e280462cdc96272bdd7b11b 0 test.txt
</code></pre></div></div>
<p><strong>Create new file in empty folder and add it to index</strong><br />
Let’s create a new empty file in the empty folder and add it to the index.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cd folder
$ echo "test" >> 2.txt
$ cd ..
$ git add .
</code></pre></div></div>
<p><strong>Check Git’s index</strong><br />
The newly created file 2.txt is tracked by Git now by using the relative path to the file.
The hash of test.txt has not changed since the content hasn’t changed at all.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git ls-files <span class="nt">--stage</span>
100644 9daeafb9864cf43055ae93beb0afd6c7d144bfa4 0 folder/2.txt
100644 95306f63471907a92e280462cdc96272bdd7b11b 0 test.txt
</code></pre></div></div>
<p><strong>Create another new file</strong><br />
Let’s create another new file in our repository. For simplicity reasons we will just copy an existing file and add it to the index since we already know that the file will not be tracked otherwise.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>cp test.txt newText.txt
<span class="nv">$ </span>git add <span class="nb">.</span>
</code></pre></div></div>
<p><strong>Check Git’s index</strong><br />
As we can see know the file has been added to the index. But have a closer look at the hash values of the files. They are equal! But why is that? You might have wondered why Git creates hashes of the files and how Git tracks changes of the files. This question will be answered in another blogpost later and is a very important concept. But for short: if two tracked files contain the very same content, the hash values will always be equal.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git ls-files <span class="nt">--stage</span>
100644 9daeafb9864cf43055ae93beb0afd6c7d144bfa4 0 folder/2.txt
100644 95306f63471907a92e280462cdc96272bdd7b11b 0 newText.txt
100644 95306f63471907a92e280462cdc96272bdd7b11b 0 test.txt
</code></pre></div></div>
Toggle Sidebars using CSS and @keyframes2015-08-01T00:00:00+00:00http://blog.stekoe.de/2015/08/01/toggle-sidebar-using-css-and-animations<p>Most modern websites do have a navigation pane on their left side which contain a logo and links.
On small screens the size of such a navigation pane takes too much space on screen and should not be painted.
Hence, some smart people invented the so called “Hamburger”-Icon which indicates a user that the navigation can be toggled.
On most websites this mechanism is implemented using jQuery’s <code class="highlighter-rouge">animate()</code>.</p>
<!-- more -->
<p>But the effect can be achieved by using CSS only.</p>
<p>One can think of adding different stati to the website, <code class="highlighter-rouge">navigationIsHidden</code> would be one of them.
So by adding <code class="highlighter-rouge"><span class="nt"><html</span> <span class="na">class=</span><span class="s">"navigationIsHidden"</span><span class="nt">></span></code> the entire HTML document <em>knows</em> that the navigation bar should not be rendered and elements have to react on this state.
Other elements like top navigation or content area are allowed to increase their size to full window width now to close the gap which was used by navigation before.</p>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">html</span><span class="nc">.navigationIsHidden</span> <span class="p">{</span>
<span class="nt">aside</span> <span class="p">{</span>
<span class="nl">position</span><span class="p">:</span> <span class="nb">fixed</span><span class="p">;</span>
<span class="nl">top</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
<span class="nl">left</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
<span class="nl">width</span><span class="p">:</span> <span class="m">240px</span><span class="p">;</span>
<span class="nt">right</span>
<span class="p">}</span>
<span class="nt">topNavigation</span> <span class="p">{</span>
<span class="nl">padding-left</span><span class="p">:</span> <span class="m">0px</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nt">html</span><span class="nc">.navigationIsHidden</span> <span class="p">{</span>
<span class="nt">aside</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">topNavigation</span> <span class="p">{</span>
<span class="nl">padding-left</span><span class="p">:</span> <span class="m">0px</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2015-08-01-toggle-sidebar-using-css-and-animations/layout.png" target="_blank" class="image ">
<img src="/assets/images/posts/2015-08-01-toggle-sidebar-using-css-and-animations/layout.png" alt="Image" />
</a>
</figure>
Status 400 when using AJAX, JSON and Spring MVC2014-12-01T00:00:00+00:00http://blog.stekoe.de/2014/12/01/status-400-when-using-ajax-json-and-spring-mvc<p>I recently faced a problem using Spring MVC and AJAX calls.
Whenever I tried to send JSON data via jQuery’s <code class="highlighter-rouge">$.ajax()</code> function, my Spring MVC application returned HTTP status 400 “The request sent by the client was syntactically incorrect”.
My first attempt to solve this problem was – of course – browsing the web, especially http://stackoverflow.com/ (SO).
But since finding a proper solution was not that easy, I am going to write down the problems I faced and finally the solution.</p>
<!--more-->
<p>First of all I have implemented a controller like this:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MyController</span> <span class="o">{</span>
<span class="err"> </span> <span class="err"> </span> <span class="nd">@RequestMapping</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="s">"/member"</span><span class="o">,</span> <span class="n">method</span> <span class="o">=</span> <span class="o">)</span>
<span class="err"> </span> <span class="err"> </span> <span class="kd">public</span> <span class="nd">@ResponseBody</span> <span class="n">String</span> <span class="nf">post</span><span class="o">(</span><span class="nd">@Valid</span> <span class="nd">@RequstBody</span> <span class="n">Member</span> <span class="n">member</span><span class="o">)</span> <span class="o">{</span>
<span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="err"> </span> <span class="c1">// ...</span>
<span class="n">Do</span> <span class="n">whatever</span> <span class="n">you</span> <span class="n">want</span>
<span class="err"> </span> <span class="err"> </span> <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The class Member is defined as follows:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Member</span> <span class="o">{</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">id</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">name</span><span class="o">;</span>
<span class="kd">public</span> <span class="nf">Member</span><span class="o">(</span><span class="n">String</span> <span class="n">id</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">id</span> <span class="o">=</span> <span class="n">id</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Whenever one executes an AJAX call with jQuery in order to create a new member, the application returns HTTP error 400.
But why does this happen? First let’s have a look at the jQuery code:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">data</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">id</span><span class="p">:</span> <span class="s2">""</span><span class="p">,</span>
<span class="na">name</span><span class="p">:</span> <span class="s2">"Hans Sarpei"</span>
<span class="p">};</span>
<span class="nx">$</span><span class="p">.</span><span class="nx">ajax</span><span class="p">({</span>
<span class="na">url</span><span class="p">:</span> <span class="nx">form</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">'action'</span><span class="p">),</span>
<span class="na">data</span> <span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">data</span><span class="p">),</span>
<span class="na">contentType</span><span class="p">:</span><span class="s2">"application/json; charset=utf-8"</span><span class="p">,</span>
<span class="na">dataType</span><span class="p">:</span><span class="s2">"json"</span><span class="p">,</span>
<span class="na">type</span><span class="p">:</span> <span class="s1">'POST'</span>
<span class="p">});</span>
</code></pre></div></div>
<p>When the AJAX call is executed, a POST request with JSON data is sent to the application.
Spring MVC decodes the JSON data and tries to map it to the desired Object–in this case “Member”.
But it seems that the framework fails at this point.
So what is the problem?</p>
<p>Most possible solutions found on SO stated that the JSON object definition is malformed and therefore not valid JSON.
Hence Spring MVC won’t be able to decode it: <code>{name: "Hans Sarpei"}</code> is not a valid JSON object, but <code>{"name":"Hans Sarpei"}</code> is (mind the double-quoted field definition).</p>
<p>Since no solutions mentioned above solved my problem, I started to investigate my code and found the problem.
In the class Member I have defined a non-standard constructor and a few getters and setters.
Since the class does not have a standard constructor, Spring MVC seems to not be able to decode the JSON @RequestBody.
Hence, I implemented a standard constructor and everything went smooth.</p>
FakeSMTP: A local mail server for testing purposes2014-06-08T00:00:00+00:00http://blog.stekoe.de/2014/06/08/fakesmtp-a-local-mail-server-for-testing-purposes<p>I recently found a very handy tool which allows one to set up a simple mail server which runs on local host for testing purposes. Since I currently develop a web application which has to send emails on registration or other notification events, I was looking for a simple tool which allows me to simulate a simple mail server running on my local machine. While I was browsing the internet I found different solutions. One was to use the mail server which is shipped with every Mac OS copy: Postfix. But I just wanted to have a nice UI like the Fake Mail App “<a href="http://hamster.volker-gringmuth.de">Hamster</a>” on Windows. Then I stumbled apon “<a href="http://nilhcem.github.io/FakeSMTP/">FakeSMTP</a>”. This tool does exactly what I was looking for!</p>
<!-- more -->
<h2 id="short-overview">Short overview</h2>
<p>FakeSMTP is written in Java and is shipped free in a single Jar-Archive under the BSD license. In order to start the SMTP server one has different options: either one uses the implemented UI by starting the Jar via a double click or via <code class="highlighter-rouge">java -jar smartSMTP.jar.</code> Or one uses the command line tool which is implemented as well. The available options are as follows (Version 1.10):</p>
<pre>usage: java -jar fakeSMTP-1.10.jar [OPTION]...
-a,--bind-address IP address or hostname to bind to. Binds to
all local IP addresses if not specified. Only
works together with the -b (--background)
argument.
-b,--background If specified, does not start the GUI. Must be
used with the -s (--start-server) argument
-m,--memory-mode Disable the persistence in order to avoid the
overhead that it adds
-o,--output-dir Emails output directory
-p,--port SMTP port number
-r,--relay-domains Comma separated email domain(s) for which
relay is accepted. If not specified, relays to
any domain. If specified, relays only emails
matching these domain(s), dropping (not
saving) others
-s,--start-server Automatically starts the SMTP server at launch
</pre>
<p>The cli offers one a bit more option as the UI but nevertheless this article concentrates on the use of the UI since one can see all important aspects there as well: Received mails, an SMTP log and the last received message including the full email header.</p>
<h2 id="the-ui">The UI</h2>
<p>In the following paragraphs I will shortly describe the contents of the UI and its functions.</p>
<h3 id="mails-list">Mails list</h3>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2014-06-08-fakesmtp-a-local-mail-server-for-testing-purposes/fakesmtp-mails.png" target="_blank" class="image ">
<img src="/assets/images/posts/2014-06-08-fakesmtp-a-local-mail-server-for-testing-purposes/fakesmtp-mails.png" alt="Image" />
</a>
</figure>
<p>When one starts the UI one is able to set the listening port of the server. In my case I have set it to port 1234 as the default SMTP port is already used on my Mac. Then I selected a folder where SmartSMTP will save all the received emails to. The emails will be saved in .eml format which is readable by all common mail applications like Apple Mail, Outlook, Thunderbird,… In addition to saving the emails to disc, a list of received emails is shown in the lower half of the UI. The list updates immediately when the SmartSMTP server has received an email (see picture 1). One useful function is to open the received emails by just double clicking on them. In this case the standard mail application will open and show the received message.</p>
<h3 id="smtp-log">SMTP log</h3>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2014-06-08-fakesmtp-a-local-mail-server-for-testing-purposes/fakesmtp-log.png" target="_blank" class="image ">
<img src="/assets/images/posts/2014-06-08-fakesmtp-a-local-mail-server-for-testing-purposes/fakesmtp-log.png" alt="Image" />
</a>
</figure>
<p>The SMTP log section is very useful if you face problems connecting to FakeSMTP server. I faced the problem, that the mail client I use in my web application did not send a correct hostname to the mail server which ended up in an exception since the SMTP command <code class="highlighter-rouge">EHLO hostname</code> is invalid and must contain a valid hostname instead of a placeholder like “hostname”. I solved this issue by adding the property <code class="highlighter-rouge">mail.smtp.localhost = localhost</code> to the list of properties in my Bean configuration.</p>
<h3 id="last-message">Last message</h3>
<p>This section is useful when one just wants to take a detailed look on the last received email. When one opens up the section “last message”, one will see a big textfield containing the full email which the server received last including the full header of the mail.</p>
<h2 id="conclusion">Conclusion</h2>
<p>FakeSMTP is a very cool tool if one wants to simulate a very simple and rudimentary email server which accepts mails. The application shows the received emails in a very comfortable way and also allows to read the received mails very easy. If one wants to take a detailed look on the SMTP commands which are run this is also possible by using the SMTP log section. FakeSMTP is <a href="https://github.com/Nilhcem/FakeSMTP">hosted at Github</a> and can be downloaded there as well.</p>
How to set up a remote git repository at shared hosters like All-Inkl.com2013-07-14T00:00:00+00:00http://blog.stekoe.de/2013/07/14/how-to-set-up-a-remote-git-repository-at-shared-hosters-like-all-inkl-com<p>Github has some great features and I do not want to miss them, but I am not willing to pay $7 per month for a “micro” account in order to set up a private repository.
Well, the $7 do not contain just the private repository but also a wiki, issue tracker and so on, but this is not what I wanted to have.
My plan was to have a hidden repository which is not visible to the public but usable by me – and only by me.</p>
<p>Hence, I started to investigate wether my (already existing) webhoster allows to create git repositories on the shared servers.
As All-Inkl.com (this is my current hoster) already offers SSH access in the so called “Private Plus” package I own, I just typed the common command <code>git</code> into the shell.
And guess what? It just worked.
So I started to create my own private git repository via SSH on my own:</p>
<!--more-->
<p>The first step was to set up the server properly.
As my hosting package mentioned above is a webhosting package, all data in my home folder located at <code>/www/htdocs/stekoe</code> is accessible via a browser and url.
In order to avoid others to access the git repository, I moved all my homepage related files to a new subdirectory <code>www</code> and configured the urls to point at this directory instead of the home directory.
This was the first step to do.</p>
<p>Now I started to build a directory structure for the git repository (or repositories – always think of upcoming requirements).
I quickly decided to create another subdirectory just aside of the new <code>www</code> directory named <code>git-repos</code>.
This directory will contain all my private repos from now on!</p>
<p>The directory structure looks like this now:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/www/htdocs/stekoe/www <-- Containing my websites
/www/htdocs/stekoe/git-repos <-- Containing private git repos
</code></pre></div></div>
<p>After changing into the <code>git-repos</code> directory, I created a new subdirectory for my first project.
Let us call it <code>myPrivateRepo</code> in this article.
Inside the newly created folder I had to create a new git repository.
As this repository is just about to store and versioning my code without having an own working copy and therefore no work tree (unversioned or files with changes).
In order to create such a “bare” repository just fire the command <code>git --bare init</code>.
Git will now initialize a new and empty git repository in the directory <code>myProvateRepo</code>.
That’s it.
We are done here on our server.</p>
<h2 id="using-a-new-local-repository">Using a new local repository</h2>
<p>The next step is to create a local(!) git repository on your Computer – you may also use an existing one (that’s what I did).
But let us start from scratch: Create a new folder anywhere on your hard disc where you want to have your working directory for your awesome project.
I will do this on my desktop: <code>mkdir awesomeProjekt</code>.
Now we want to check out the repository on our server.
Let us do it: <code>git clone ssh://<ssh-user>@stekoe.de/www/htdocs/stekoe/git-repos/myPrivateRepo</code>.
You see one important thing: the path after the url hast to be the absolute path on filesystem to your git repository! It took me several tries to figure this out...</ssh-user></code></p>
<p>Git clones the remote repository to your computer now and will finish with a warning:</p>
<blockquote>
<p>warning: You appear to have cloned an empty repository.</blockquote></p>
</blockquote>
<p>That’s right.
Our git repository on our server is empty, but we will now do our first commit.
Change into the directory <code>myPrivateRepo</code> which has been created by the clone command of git and create an new file.
I have added a “readme.txt” with a content of”Hello World!”.
Now type <code>git status</code> and you will see that git has found the unversioned (untracked) file.
Just add it to the list of files to be committed via a <code>git add "your file"</code>.
After adding the file to the commit list, commit the file either via <code>git commit -m "Added a file"</code> or <code>git commit</code>.
You have to add a commit message.
This is mandatory.</p>
<p>After committing all files you are done, right? No! But why? You have committed the file only to your local repository! In order to push it to the remote repository on the server you have to do one step more: <code>git push</code>.
Whoops! It fails! But again: why? The answer is pretty easy: Remember we have created an <em>emtpy</em> repository on the server? It has no branches or any structure…
This means that you have to tell the remote repository where to put the first commit you are doing…
Let us try again: <code>git push origin master</code>.
“origin” is the (standard) name of our remote repository and “master” the branch we want to commit our changes to.
Everything should run fine now and we have made our first commit to local and remote repository!</p>
<h2 id="using-an-existing-project-or-local-repository">Using an existing project or local repository</h2>
<p>What happens if we have already some sources or a local git repository? If we already have some source files which we want to add to a git repository just change into the root folder of the project you want to commit and create a new git repo via <code>git init</code>.
Then commit all the files to your local repository via <code>git add .</code> and <code>git commit -m "Init commit"</code>.</p>
<p>The next step is to connect your local repo to the remote repo.
This is fairly easy:
<code class="highlighter-rouge">git remote add origin ssh://<ssh-user>@stekoe.de/www/htdocs/stekoe/git-repos/myPrivateRepo</code>.
This command tells your local repository that a remote repository is located at the given URL and that you want to name it “origin” for readability.
Now you can use the <code>git push</code> command to push changes to the repository and <code>git pull</code> to receive changes committed (by another user or whatever) from the repository.
That’s it :)</p>
Enable User Management in Jenkins2013-07-08T00:00:00+00:00http://blog.stekoe.de/2013/07/08/enable-user-management-in-jenkins<p>Just a short memo to all users who are looking for the “Manage Users” section in Jenkins… Here is how to activate it in ten easy steps:</p>
<ol>
<li>Klick on “Manage Jenkins”</li>
<li>Then on “Configure Global Security”.</li>
<li>Then activate “Jenkin’s own user database” beyond “Security Realm”</li>
<li>Now scroll down to “Authorization” and activate “Matrix-based security”. You will find one entry for the user “Anonymous”.</li>
<li>Activate all checkboxes for this user (hint: use the tiny litte icon at the far right of the table row).</li>
<li>Hit “Save”.</li>
<li>Got back to “Manage Jenkins” and you will find a new entry named “Manage Users”.</li>
<li>Create a new user and copy it’s username</li>
<li>Add the user (via it’s username) to the list mentioned in step 4.</li>
<li>Turn off all checkboxes for the new user and remove all checkboxes for the user “Anonymous”. Done.</li>
</ol>
JUnit 4 does not run latest changes on tests2013-06-17T00:00:00+00:00http://blog.stekoe.de/2013/06/17/junit-4-does-not-run-latest-changes-on-tests<p>Today I faced the problem that newly created JUnit test cases were not run by JUnit in Eclipse.</p>
<p>As we are using Eclipse in combination with Maven we figured out that this was caused by a configuration problem of the project settings in Eclipse.</p>
<!--more-->
<p>Maven’s default test output directory is <code>target/test-classes</code> whereas Eclipse puts its output to <code>target/classes</code> which is the default configuration.
In order to get my JUnit 4 tests run again, I deleted the <code>target/classes</code> folder and reconfigured my project configuration by selecting the project, hitting <kbd>Alt</kbd> + <kbd>Return</kbd>.
In the properties window navigate to “Java Build Path” and open up the “Source” tab.
Now select the entry for your tests <code>whatever/src/test/java</code> and have a look at the textfield at the bottom.
The content has to look like <code>whatever/target/test-classes</code> and not as in many cases <code>whatever/target/classes</code>.
Change it to <code>whatever/target/test-classes</code>, hit ok and you should be ready to go.</p>
Side note: Battery Status of external devices are always approximated!2013-06-12T00:00:00+00:00http://blog.stekoe.de/2013/06/12/did-you-know-battery-status-of-external-devices-are-always-approximated<p>While I was playing around with iStatPro, a monitoring tool for Mac OS X, I figured out that the battery status was displayed totally wrong.
Mac OS X showed me a percentage of 53% remaining battery power, but iStatPro reported 32%.
How comes?</p>
<p>After some investigation I figured out that it is not easy to calculate the remaining power of a battery when you don’t know what type of battery is used.
What does that mean? Each battery type (NiMh, Alkaline, …) has its own “discharge curve” which leads to problems when implementing algorithms to calculate the current battery level.
Some battery types like Alkaline have a very linear curve whereas the voltage of a NiMh battery drops dramatically at the start and then does not change much until the very end when it fells down drastically.
In addition to that some battery types react on even little changes of temperature which may also lead to false information.</p>
Activating "Expand selection to" shortcuts for Eclipse on Mac OS X2013-05-25T00:00:00+00:00http://blog.stekoe.de/2013/05/25/activating-expand-selection-to-shortcuts-for-eclipse-on-mac-os-x<p>When using Eclipse on Windows the IDE offers you a very useful shortcut to select lines and code blocks at once. This feature is called “Expand selection to…” and you can trigger it by using the keys <kbd>Alt</kbd> <kbd>Shift</kbd> <kbd>Arrow Keys</kbd>.</p>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2013-05-25-activating-expand-selection-to-shortcuts-for-eclipse-on-mac-os-x/1140_disable_system_shortcuts.png" target="_blank" class="image ">
<img src="/assets/images/posts/2013-05-25-activating-expand-selection-to-shortcuts-for-eclipse-on-mac-os-x/1140_disable_system_shortcuts.png" alt="Image" />
</a>
</figure>
<p>The corresponding key bindings on Mac OS are as follows: <kbd>Ctrl</kbd> <kbd>Shift</kbd> <kbd>Arrow Keys</kbd></p>
<p>But there is one problem with this key binding: It is usually bound to a Mac OS feature to switch Desktops or to open Mission Control (aka Exposé). You have to deactivate this features in the settings of Mac OS as shown in the figure on the right.</p>
<p>After disabling the marked key bindings you will be able to use the “Expand Selection to…” feature in Eclipse on Mac OS. Enjoy!</p>
Java equals() vs. hashCode() methods2013-02-07T00:00:00+00:00http://blog.stekoe.de/2013/02/07/java-equals-vs-hashcode<p>I recently stumbled upon the two methods <code class="highlighter-rouge">equals()</code> and <code class="highlighter-rouge">hashCode()</code> in Java while I was implementing a class which should be able to be comparable.
My first try was just to use the common <code class="highlighter-rouge">equals()</code> method in <code class="highlighter-rouge">java.lang.Object</code> which lead to the problem that the method always returned false–but why?
Lets have a look at the implementation of the <code class="highlighter-rouge">equals()</code> method in <code class="highlighter-rouge">java.lang.Object</code>:</p>
<script src="https://gist.github.com/d9d6c83f421a1c6ea41d.js"> </script>
<p>What do these three (or one in particular) lines do? Well, each Object is located in main memory as long as any part of the software has an active reference to the object, otherwise it will be removed by the garbage collector.
So each variable points to the location of the object in memory.
Hence, the line above compares wether the location of the compared objects are equal or not and if they are equal the compared objects are equal.
You may think that this is fine, but we will see: It’s not!</p>
<!--more-->
<h2 id="equals">equals()</h2>
<p>In order to explain the behaviour of <code class="highlighter-rouge">equals() and </code>hashCode()` we need to introduce a example class as follows:</p>
<script src="https://gist.github.com/5127c56ef0df9e8890dd.js"> </script>
<p>The class represents a simple type of a Employee who has a number, name and a birthday.–At this point we ignore the fact that type String is not the best choice to be used to store a date (instead of using Calendar), but thats another story.</p>
<p>What we want to do now is to run some tests using the class above and the methods <code class="highlighter-rouge">equals()</code> and hashCode().
Therefore we create a new class which will implement some JUnit tests like this one:</p>
<script src="https://gist.github.com/60842a79057ad60edfdb.js"> </script>
<p>What is done in the code above? We create a new instance of type Employee and fill it with some example data.
Then we compare the newly generated Object named “burns” with itself.
Referring to the description in the Java API how <code class="highlighter-rouge">equals()</code> works, the result of the comparison will be true.
As we use JUnit, we run an asserTrue() in order to get notified if the expression which is passed to the asserTrue() method returns false.
As we compare the very same object here which is located at the same point in main memory, <code class="highlighter-rouge">equals()</code> will return true.
But lets go on and have a look at the following situation:</p>
<script src="https://gist.github.com/3c37107bc114df8483b1.js"> </script>
<p>We have two objects, burns and burns_double which do have exactly the same “content”–in case of objects we speak of “states”.
BUT: if we now compare these two objects by using the <code class="highlighter-rouge">equals()</code> method, the JUnit test will fail, why? Again, let’s go one step back and think again of how <code class="highlighter-rouge">equals()</code> works: It just compares wether the passed in references are pointing to the same location in main memory.
As we do have two different objects which have their own separated locations in memory, the common implementation of <code class="highlighter-rouge">equals()</code> will return false, although the object states are equal.
The current implementation of Employee needs to be extended in order to achieve the desired result.
We have to override the <code class="highlighter-rouge">equals()</code> method on our own, so that it checks wether we are dealing with the very same object or wether the objects have equal states.
In order to start to implement our own <code class="highlighter-rouge">equals()</code> method, we have to have a look on the source code of java.lang.Object as you have to fulfill some requirements when overriding the <code class="highlighter-rouge">equals()</code> method:</p>
<blockquote>
<p>For any non-null reference value
x, x.equals(x) should return true.</p>
<p>For any non-null reference value x,
x.equals(null) should return false.</p>
</blockquote>
<p>Lets start to implement the basic requirements mentioned above:</p>
<script src="https://gist.github.com/f49d3a31fec2c8301b68.js"> </script>
<p>What have we done here? Lines three and four implement the same operation as the java.lang.Object#equals() method.
We have discussed them above.
Lines five and six fulfills the requirement that “x.equals(null) should return false”.
Lines seven and eight compare wether the current object has the same type as the object which has been passed into the <code class="highlighter-rouge">equals()</code> method.–Wait! Why don’t we use “instanceof” here?</p>
<p>Let’s assume that we have a specialised version of class Employee called Manager and we create an object of each of the classes with the same content.
If we now perform a “instanceof” call on the Manager-Object like obj instanceof Employee[/cci] it will return true.
But in our case we do not want to check wether the object is an instance of a type but if its the same type (no specialised one) and state.
Hence, “instanceof” would not fulfill this and is not sufficient.</p>
<p>By now we have implemented some generic comparison in the <code class="highlighter-rouge">equals()</code> method.
But we still do not check for the state of the object.
Therefore we start to implement this now:</p>
<script src="https://gist.github.com/aecbedc3beb9f8eefa7a.js"> </script>
<p>Now we have implemented state checking as well.
For each field in class Employee that we want to be part of the comparison, we have written an if block in our <code class="highlighter-rouge">equals()</code> method.
As the code contains just some basic logic, just read and try to understand it–it is really straight forward.</p>
<p>Now, if we rerun our JUnit test “iShouldBeEqual()”, the JUnit test will pass which means that we are done, or? Sorry for asking a leading question as the answer is obvious: No, we are not done yet! But why?! Well, we have to refer to the documentation of java.lang.Object again.
At the end of the documentation block of the <code class="highlighter-rouge">equals()</code> method you will find the following sentence:</p>
<blockquote>
<p>Note that it is generally necessary to override the {@code hashCode} method whenever this method is overridden, so as to maintain the general contract for the {@code hashCode} method, which states that equal objects must have equal hash codes.</p>
</blockquote>
<p>Hence, I will introduce the <code class="highlighter-rouge">hashCode()</code> method in short in the following chapter and describe where it is used and why it is important to implement the <code class="highlighter-rouge">hashCode()</code> method as well.</p>
<h2 id="hashcode">hashCode()</h2>
<p>When you think of hash codes some other terms might get into your mind like “hash map”, “hash set” or “hash table”.
This are basically the fields where <code class="highlighter-rouge">hashCode()</code> method is used and why it is necessary to override the implementation of it.
The current implementation of our example just contains the <code class="highlighter-rouge">equals()</code> method which is currently comparing objects and their states.
As soon as we want to use the type Employee in combination with a HashMap or HashSet, we run into problems which are not obvious at first sight.</p>
<p>Although I will not introduce HashMap and HashSet in detail, I will give you the most important information about these two Collections in Java and in general.
HashMaps and HashSets are special types of Collections which are using hash codes in order to address contained elements in the collection in a fast and efficient way.
HashMaps can contain any amount of objects, even equal objects more than one time.
HashSets may only contain objects once(!).
If you pass an object to a HashSet which is already part of the HashSet, the old value will be overwritten with the new one (cf.
java.util.HashMap(sic!) ll.
468).
That’s the major difference between HashMaps and HashSets, but what about the term “Hash”?</p>
<p>If you take a deeper view into the source code of HashMaps and HashSets you will see that both use some kind of table which contains a key and a value.
The key corresponds to the hash of an stored object and the value is the stored object itself.
But why do we use hashes instead of just looking up the objects directly? To keep the answer as short as possible, ask yourself: What is faster, comparing computers by their part numbers (model identifiers or whatever) or by comparing each part inside the computer? Of course it is much faster to compare the part number of the whole PC instead of each part itself.
And thats why HashTables have been invented.
In case of cost reduction (in this context costs do not have any economical aspect but express the time an algorithm lasts), hashes have evolved and are much easier and faster to use than anything else.
In order to keep the advantages of HashTables up, it is necessary that hashes for objects are as unique as possible.
If we have more than one object with the same hash we have to deal with collisions of hash codes.
If multiple objects which are passed into a HashCollection have the same hash code in Java, they will be added to a single chained list of table entries:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Key Value
==== =======================================================
0001 "object 1" --> "object 2" --> "object 3" --> null
0002 null
0003 "object 4" --> null
....
</code></pre></div></div>
<p>If each object returns the same hash code, all objects would be added to one key containing all objects.
This would slow down the hash table dramatically.</p>
<p>One other thing you may have noticed is that you can check wether objects are not equal by comparing their hash codes but you can not be sure wether objects are equal if you just compare their hash code, since two totally different objects may return the very same hash code.</p>
<p>Let’s implement the <code class="highlighter-rouge">hashCode()</code> method now.
One good rule for implementing the <code class="highlighter-rouge">hashCode()</code> method is to use any field you have used in the <code class="highlighter-rouge">equals()</code> method in <code class="highlighter-rouge">hashCode()</code> again.
In case of our example this would be the fields “itsName”, “itsBirthday” and “itsPersonnalNumber”.
Our <code class="highlighter-rouge">hashCode()</code> method will look as follows:</p>
<script src="https://gist.github.com/d77636b4cb6167fab4bc.js"> </script>
<p>What do we do here? We are calculating a hash code as integer value by adding and multiplying different values.
Line four initialises the result by setting the variable result to 1 but this value is arbitrary.
The next lines (five and six) calculate the hash codes of the fields which are of type String by using the <code class="highlighter-rouge">hashCode()</code> method implemented in java.lang.String or zero if the field values are null.
Line seven just adds the value of the integer of field “itsPersonnalNumber” to the result variable.
Finally in line eight the computed result is returned as the hash code of the current object.</p>
<p>What about line three? Why do we use the prime 31 here? As Josuha Bloch (p.48) says, 31 is used because it is an odd number and in case of overflowing multiplication, “information would be lost, as multiplication by 2 is equivalent to shifting”.
Though, the usage of a prime is not clear, but traditional.
This means, we are allowed to use any number we want to use if it is not even.</p>
<h2 id="conclusion">Conclusion</h2>
<p>In this blog post you have learned why it might be necessary to override the <code class="highlighter-rouge">equals()</code> method in your implementation and why it is necessary to override <code class="highlighter-rouge">hashCode()</code> method as well.
I have tried to explain the behaviour of both methods as simple as possible and in a way I got used to the meanings of both methods myself.
If you want to get more into detail, I recommend you to read the source code and documentation of the classes touched in this blog or to get your hands on a book which is focused on this topic (i.e.
Effective Java, Second Edition by Joshua Bloch.
Addison-Wesly Pearson Education.
ISBN-13: 978-0-321-35668-0).</p>
Keeping phpMyAdmin up-to-date2012-12-24T00:00:00+00:00http://blog.stekoe.de/2012/12/24/keeping-phpmyadmin-up-to-date<p>I recently got a message from my local phpMyAdmin installation to update to the most current version.
I then headed to the web page of <a href="http://www.phpmyadmin.net" target="_blank">phpMyAdmin</a> and started to download the latest stable Release.
But then I recognized, that phpMyAdmin has moved its source to <a href="http://www.github.com" target="_blank">GitHub</a>.
So why not checking out the code and perform a <code>git pull</code> in order to update the phpMyAdmin installation next time?</p>
<!--more-->
<p>So what I did was: Heading to the folder which contains the current phpMyAdmin installation and backing up the config.inc.php file.
This is necessary as this file contains all your configuration data for phpMyAdmin.
After you are sure that you have backed-up the config file properly, clear the entire folder.
This is necessary as the <code>git clone</code> command needs an empty folder.
I achieved this by running <code>rm -rf ./</code>.
After you have cleared the folder, you can run the <code>git clone</code> command: <code>git clone https://github.com/phpmyadmin/phpmyadmin.git ./</code></p>
<p>The cloning takes up to 10 minutes, depending on your connection speed.
After you have cloned the repository, you have checked out the most current development version of phpMyAdmin.
When you just want to use stable releases, you have to run the following command as well: <code>git checkout -t origin/STABLE</code>.</p>
<p>Now you have checked out the most recent stable version of phpMyAdmin.
The last step is to move back your <code>config.inc.php</code> into the phpMyAdmin folder.
Voila: Your phpMyAdmin installation works again.
If you want to update your installation now, just run a <code>git pull</code> and the most recent sources will be checked out.</p>
<p>Btw.: Happy holidays!</p>
[Updated] Writing papers and doing proper backup?!2012-11-30T00:00:00+00:00http://blog.stekoe.de/2012/11/30/writing-paper-and-doing-proper-backup<p>This article is about how to save papers and how to back it up properly.
I am currently writing some papers on different topics and as I am studying Information Systems – Wirtschaftsinformatik – I am aware of hardware or software crashes.
Therefore I have found a very simple but effective way in how to get rid of the threat of losing my entire work.</p>
<!--more-->
<p>Since I am writing my papers using LaTeX it is very easy to set up a proper backup method.
LaTeX documents are written in plaintext format.
Nevertheless you can perform my backup method if you are using Microsoft Word or similar software, too.
Anyways: This article is about how to set up Eclipse using EGit for versioning my work and Dropbox as my backup drive.</p>
<p>Let’s assume you want to write a paper using LaTeX then you should use Eclipse as LaTeX-Editor since you can integrate Git, SVN or CVS into Eclipse flawlessly.
When you start to work using Eclipse, set your workspace location to a subfolder of your local Dropbox (or whatever you are using) folder.
Everything you are doing in Eclipse now is synchronised into the Cloud.
You will never loose you work anymore – unless Dropbox will collapse ;).
If you are a very paranoid user you might also consider to encrypt your workspace folder, because then even the Dropbox staff won’t be able to read your papers and steal them.</p>
<p>This was the first thing to set up.
Second is to use Git! – Oh god, why git, it is just another hyped versioning System!!! Yes, it is, but: You do not have to set up a server, keep it running and so on.
You just have to create a local repository (in a folder synced to Dropbox) and everything is fine.
And since Eclipse provides a plugin for Git, its incredibly easy! Just open “Help” -> “Install new Software…” in Eclipse, select the update site of your current Eclipse distribution and look for “EGit” plugin.
Select it and install.</p>
<p>After you have installed EGit and restarted Eclipse, perform a right click on your project in the Package Explorer, choose “Team” and then “Share Project…”.
In the opening window choose “Git”, hit next.
In the upcoming window check the box “Use or create repository […]”, hit the button “Create Repository” then hit “Finish”.
You have set up your own, local Git Repository now!</p>
<p>At this point you can start to work on your paper.
Every time you have finished work or you want to mark a milestone, you can check in your changes to your repository.
You are able to switch between revisions since you are using a versioning system! To commit your changes, right click on your project, choose “Team” and then “Commit”.
Check the files at the bottom which you want to commit, enter a message at the top (e.g.: Rewritten first chapter) and hit commit.
You now have committed your changes and you will be able to switch between different versions of your work.
For instance: When you have deleted a paragraph, saved your changes and can’t get it back, you can just switch back to the previous revision of the file! And as the repository is saved in the same folder as your project, it is synchronised to the cloud at the same time.</p>
<p>I think, that this method is very simple and very handy since it automagically backs up your data into a cloud and you have the opportunity to save different versions of your work to a local repository which has been set up in seconds without using a server.
It just works :)</p>
<p style="text-align: left;"><strong>Edit: </strong>In addition to saving your work to a Git-Repository and syncing it with Dropbox, you may also add your Dropbox folder to your TimeMachine if you are using Mac OS.
Every time you plug in your TimeMachine Backup Drive, your work will be backed up one more time.
Or you run a "rsync -acv –delete" manually.
[Thanks to Florian :)]</p>
<p style="text-align: left;"><strong>Edit 2: </strong>I experienced some major issues while using this concept to backup my thesis.
The issues were caused by Eclipse and Dropbox.
Eclipse seems to constantly write into files in workspace while it is running and Dropbox tries to upload the file every time.
As Eclipse writes nearly every second something to the workspace, Drobox.app uses 100% of CPU.
Just disable Dropbox while writing your thesis/paper/text and restart it after you have finished your work.</p>
CakePHP: Tree Behavior2012-05-21T00:00:00+00:00http://blog.stekoe.de/2012/05/21/cakephp-tree-behavior<p>Im einführenden Beitrag zu CakePHP habe ich bereits kurz über das Tree Behavior gesprochen und kurz angedeutet, wofür dies verwendet werden kann.
Da dieses Behavior zum einen ein Kern Behavior ist (also bei CakePHP standardmäßig dabei), aber auch regen Gebrauch findet, widme ich diesem teilweise komplizierten Behavior einen dezidierten Beitrag mit Anwendungsbeispiel und ausführlichen Erklärungen.</p>
<!--more-->
<p>Das Tree Behavior findet immer dann Anwendung, wenn eine sortierte oder verschachtelte Liste (nested set) in einer Datenbank gespeichert werden soll.
Hierfür muss das Tree Behavior zum einen an das jeweilige Modell angehängt werden</p>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="nv">$actsAs</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span><span class="s1">'Tree'</span><span class="p">);</span>
</code></pre></div></div>
<p>und die Datenbank vorbereitet werden, da das Tree Behavior drei zusätzliche Felder benötigt.
Dies sind <em>parent_id</em>, <code class="highlighter-rouge">lft</code> (left) und <code class="highlighter-rouge">rght</code> (right).</p>
<p>Das Feld <em>parent_id</em> adressiert das übergeordnete Element in einer verschachtelten Liste oder <em>NULL,</em> wenn das aktuelle Element auf oberster Ebene sein soll.
Die Felder <code class="highlighter-rouge">lft</code> und <code class="highlighter-rouge">rght</code> dienen dazu die Reihenfolge der Elemente festzulegen.
Ebenso ist durch die beiden Felder eine einfache Suche und Abfrage über die Liste möglich (warum dies so ist, wird später deutlich).</p>
<p>Der genaue Nutzen der Felder <code class="highlighter-rouge">lft</code> und <code class="highlighter-rouge">rght</code> wird deutlich, wenn man sich die Theorie dazu anschaut:
Das Tree Behavior stützt sich auf das in der Informatik bewährte Konzept des Tiefensuchbaums oder auch <a href="http://en.wikipedia.org/wiki/Depth-first_search" target="_blank">Depth First Search (DFS)</a>.</p>
<h2 id="anwendungsbeispiel">Anwendungsbeispiel</h2>
<p>Da man eine Webseitennavigation als verschachtelte Liste auffassen kann, bauen wir unser Beispiel auf folgende Liste auf:</p>
<ul>
<li>Home</li>
<li>Universities</li>
<li style="list-style: none; display: inline">
<ul>
<li>University of Duisurg-Essen</li>
<li>University of Köln</li>
<li>University of Munich</li>
</ul>
</li>
<li>Impress</li>
<li>Team</li>
<li style="list-style: none; display: inline">
<ul>
<li>Administrators</li>
<li>Coordinators</li>
<li>Content-Assistant</li>
</ul>
</li>
</ul>
<p>Die Elemente <em>Home</em>, <em>Universities</em>, <em>Impress</em> und <em>Team</em> befinden sich auf oberster Ebene der Liste und haben daher keine Elternknoten.
Das Feld <em>parent_id</em> ist <em>NULL _(vgl.
Tabelle unten).
Überträgt man _alle</em> Elemente in eine Tabelle mit <em>Datensatz-ID</em>, <em>Titel</em> und <em>parent_id</em> Feld, erhält man folgendes Ergebnis:</p>
<table class="table table-full">
<thead>
<tr>
<th align="center">id</th>
<th>title</th>
<th align="center">parent_id</th>
<th align="center">lft</th>
<th align="center">rght</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">1</td>
<td>Home</td>
<td align="center">NULL</td>
<td align="center">1</td>
<td align="center">2</td>
</tr>
<tr>
<td align="center">2</td>
<td>Universities</td>
<td align="center">NULL</td>
<td align="center">3</td>
<td align="center">10</td>
</tr>
<tr>
<td align="center">3</td>
<td>Impress</td>
<td align="center">NULL</td>
<td align="center">11</td>
<td align="center">12</td>
</tr>
<tr>
<td align="center">4</td>
<td>Team</td>
<td align="center">NULL</td>
<td align="center">13</td>
<td align="center">20</td>
</tr>
<tr>
<td align="center">5</td>
<td>University of Duisburg-Essen</td>
<td align="center">2</td>
<td align="center">4</td>
<td align="center">5</td>
</tr>
<tr>
<td align="center">6</td>
<td>University of Cologne</td>
<td align="center">2</td>
<td align="center">6</td>
<td align="center">7</td>
</tr>
<tr>
<td align="center">7</td>
<td>University of Munich</td>
<td align="center">2</td>
<td align="center">8</td>
<td align="center">9</td>
</tr>
<tr>
<td align="center">8</td>
<td>Administrators</td>
<td align="center">4</td>
<td align="center">14</td>
<td align="center">15</td>
</tr>
<tr>
<td align="center">9</td>
<td>Coordinators</td>
<td align="center">4</td>
<td align="center">16</td>
<td align="center">17</td>
</tr>
<tr>
<td align="center">10</td>
<td>Content-Assistants</td>
<td align="center">4</td>
<td align="center">18</td>
<td align="center">19</td>
</tr>
</tbody>
</table>
<p>Doch wie kommen die Felder <code class="highlighter-rouge">lft</code> und <code class="highlighter-rouge">rght</code> zustande? Dies ist nicht ganz einfach zu erklären.
Zunächst muss man die verschachtelte Liste als Baum aufzeichnen (siehe Bild).
Ausgehend von der Wurzel (<em>NULL</em>), welche selbst nicht explizit in der Datenbank gespeichert wird, muss man jeweils den Kind-Knoten “besuchen”, welcher noch nicht besucht wurde und am weitesten links liegt.
Um dies zu verdeutlichen durchlaufen wir ein paar Elemente des Baumes:</p>
<p>Der erste linke nicht besuchte Knoten ist “Home”.
Navigiert man nun also von _NULL _zu Home, muss im Feld <code class="highlighter-rouge">lft</code> eine 1 eingetragen werden, da man erst einen Schritt gegangen ist.
Home selbst hat keine Kind-Knoten, sodass man nun zum Elternknoten zurückgehen muss.
Hierfür muss jedoch immer der Umweg über sich selbst genommen werden.
Dieser Umweg wird ebenfalls als ein Schritt gezählt und die Anzahl im Feld <code class="highlighter-rouge">rght</code> festgehalten.
Daraus resultiert der Wert 2 für das Feld <code class="highlighter-rouge">rght</code> des Home-Knotens.</p>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2012-05-21-cakephp-tree-behavior/Treebehavior.png" target="_blank" class="image ">
<img src="/assets/images/posts/2012-05-21-cakephp-tree-behavior/Treebehavior.png" alt="Image" />
</a>
<figcaption class="figure-caption">Abbildung 1: Aufgespannter Baum der Beispielnavigationsstruktur</figcaption>
</figure>
<p>Das ist der dritte Weg, den man gehen musste, also bekommt der Knoten “Universities” im Feld <code class="highlighter-rouge">lft</code> den Wert 3.
Universities hat Kinderknoten.
Hier muss jeweils wieder der am weitesten links gelegene gewählt werden: University of Duisburg-Essen.
Wenn man dort hingeht, sind wir 4 Wege gegangen.
<code class="highlighter-rouge">lft</code> ist also 4 für diesen Kind-Knoten.
Der Knoten selbst hat keine Kinder und man muss erneut den Umweg über ihn selbst gehen, <code class="highlighter-rouge">rght</code> ist daher 5.
– Das Prinzip sollte nun klar sein.</p>
<p>Sortiert man die Einträge anhand des Feldes <code class="highlighter-rouge">lft</code> oder <code class="highlighter-rouge">rght</code>, kann eine sortierbare bzw.
sortierte Liste realisiert werden.
Möchte man bspw.
Impressum und Team tauschen, so ändern sich die <code class="highlighter-rouge">lft</code> und <code class="highlighter-rouge">rght</code>-Werte für Impress, Team und alle Unterknoten von Team.
Da dies automatisch vom Framework über das Tree Behavior berechnet wird, muss man sich jedoch keine Gedanken machen.
Es reicht der Aufruf der Methode <em>moveUp($id)</em> und das Framework berechnet alle Werte selbstständig neu.</p>
<p>Durch diese beiden Felder ist es zum Beispiel auch möglich alle Kinder-Knoten eines Elternknotens zu ermitteln:
Gebe mir alle Knoten zurück, wo die <code class="highlighter-rouge">lft</code>-Werte größer oder gleich dem <code class="highlighter-rouge">lft</code>-Wert und die <code class="highlighter-rouge">rght</code>-Werte kleiner oder gleich dem <code class="highlighter-rouge">rght</code>-Wert des Elternknotens sind.</p>
Setting up a VirtualHost2012-05-08T00:00:00+00:00http://blog.stekoe.de/2012/05/08/setting-up-a-virtualhost<p>It’s been a while since I started to learn website engineering on my own, but when I tried to set up multiple hosts on my local computer I ran into problems.
Although it is very easy to set up as many hosts on your local computer as you want by using virtual hosts, I have never found a good tutorial describing it in a short but clear way.
Therefore I’ve written this one.</p>
<!--more-->
<h2 id="introduction">Introduction</h2>
<p>Whenever you start to develop multiple websites at once it might be usefull to have own, custom local domains to access the websites directly.
Let’s assume you have three websites:
You own personal homepage, one for a friend and the third one for a customer.
Then you should have three folders in your document root of your apache server containing the different sources of the websites:</p>
<ul>
<li>DOCUMENT ROOT
<ul>
<li>my-tiny-little-website</li>
<li>my-friends-website</li>
<li>customers-website</li>
</ul>
</li>
</ul>
<p>In order to access your websites you typed an URL like this into your browser bar:
“<em>http://localhost/my-tiny-little-website</em>” But woultn’t it be much nicer to have an URL like this:
“<em>http://my-tiny-little-wegsite.dev</em>”? Well, of course, since you do not have to navigate all the way long to your subfolders! And if you are using some difficult techniques like <em>mod_rewrite</em> you may run into problems when you do not use an own URL for developing your website.</p>
<p>I hope that you are spoiling to set up an own URL on you local machine at this point.
So let’s start with the procedure now.</p>
<h2 id="editing-your-hosts-file">Editing your hosts file</h2>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2012-05-08-setting-up-a-virtualhost/sudonano.png" target="_blank" class="image ">
<img src="/assets/images/posts/2012-05-08-setting-up-a-virtualhost/sudonano.png" alt="Image" />
</a>
<figcaption class="figure-caption">Fig.1: hosts file in terminal</figcaption>
</figure>
<p>Every computer regardless of wether it runs Mac OS, Windows or Linux, you will have to find the <code class="highlighter-rouge">hosts</code> file.
On Mac OS and other unix based OS it is located at <code class="highlighter-rouge">/etc/hosts</code>.
When you are using Windows you have to look for it in this folder:</p>
<p><code class="highlighter-rouge">%SystemRoot%\system32\drivers\etc\hosts.</code></p>
<p>In order to change the file you have to gain admin previliges.
Using unix bases systems, just to open up the terminal and type in <code class="highlighter-rouge">sudo nano /etc/hosts</code> and you should see an output in your terminal as shown on Figure 1.
Or try to use the command <code class="highlighter-rouge">sudo vi /etc/hosts</code>.</p>
<p>At this point you have to decide how you want to name your local website.
I found out, that it is not good to call them “<em>whatever.local</em>”, since the domain ending <em>.local leads to a multicast DNS lookup in your network and may result in longer loading times than expected.
Therefore I call my local development pages “</em>whatever.dev*”.</p>
<p>Now, when you have decided how to call your local page, you have to add the URL to your previously opened hosts file.
Type in <code class="highlighter-rouge">127.0.0.1 my-tiny-little-website.dev</code> and you are done here.
But wait! What did you just do?! Well, simple question, simple answer:
Whenever your PC tries to access a network address – no matter if its an IP or URL – it will (depending on your local settings) read in the hosts file and if there is an entry for the IP/URL your PC tries to connect to, it will replace (or route) the connection attempt to the IP address which has been entered in front of the entry.
For instance:
When you save your hosts file now and open your browser and you type in “<em>my-tiny-little-website.dev</em>” and you hit enter, your PC knows, that it has to route the request to your localhost located at 127.0.0.1.
And since your browser does an HTTP-request using port 80, your apache will answer the request.</p>
<h2 id="adding-virtual-host-to-httpdconf">Adding virtual host to httpd.conf</h2>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2012-05-08-setting-up-a-virtualhost/httpd.conf_.png" target="_blank" class="image ">
<img src="/assets/images/posts/2012-05-08-setting-up-a-virtualhost/httpd.conf_.png" alt="Image" />
</a>
<figcaption class="figure-caption">Fig.2: Apache's http.conf file</figcaption>
</figure>
<p>Adding the development URL to your hosts file was the first task to perform.
But you have to tell your apache server how to deal with the new URL.
Otherwise apache will just deliver you the default webpage in your document root directory.
To change this, find the file <code class="highlighter-rouge">httpd.conf</code> on your hard disc.
When you are using XAMPP it should be at <code class="highlighter-rouge">c:/xampp/apache/conf/httpd.conf</code>.
MAMP holds this file at the following location:
<code class="highlighter-rouge">/Applications/MAMP/conf/apache/httpd.conf</code>.
If you are running another unix based system try out this location <code class="highlighter-rouge">/etc/httpd/conf/httpd.conf</code> or search your PC.</p>
<p>Once you have found the file, open it up and add these lines at the end of it:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>NameVirtualHost *:80
<VirtualHost *:80>
ServerAlias my-tiny-little-website.dev
DocumentRoot "/PATH/TO/YOUR/HTDOCS/FOLDER/my-tiny-little-website"
</VirtualHost>
</code></pre></div></div>
<p>Add a new file into the folder “my-tiny-little-website” called index.php and add some PHP code.
Then restart apache as it needs to re-read the httpd.conf file.
When you open a browser now and type in the url “my-tiny-little-website.dev” your PHP file should be parsed and the result should be send to the browser.
You have successfully set up a virtual host!</p>
Nested category list in WordPress2012-04-04T00:00:00+00:00http://blog.stekoe.de/2012/04/04/nested-category-list-in-wordpress<p>I have just added a nested category item to our category list (on the right side of our page) and wondered why the nested item was not shown as child entry in the sidebar.
After hours of looking around in the WordPress documentation, I figured out how to get a hierarchical (nested) category list.</p>
<!--more-->
<p>The method <code class="highlighter-rouge">wp_list_categories()</code> can receive various arguments to control the output.
When you are using widgets in your templates and especially the category list widget, you can not easily open a PHP file, change the arguments as desired and upload the file again.
In order to manipulate/change the arguments you have to add filters in your function.php file of the current template.</p>
<p>As you can see in the code example at the end of this post, you may change ANY of the arguments passed to the function <code class="highlighter-rouge">wp_list_categories()</code> by just merging them to the <code class="highlighter-rouge">$args</code> array inside a special filter.</p>
<p>In the case of SystemOutPrintln.de we wanted to have a hierarchical (nested) list, instead of a plain one (shortened) as show below:</p>
<ul>
<li>Software development</li>
<li>Miscellaneous</li>
<li>OS X</li>
<li>Common</li>
</ul>
<p>We wanted the result to look like this (shortened):</p>
<ul>
<li>Software development</li>
<li>Miscellaneous
<ul>
<li>OS X</li>
</ul>
</li>
<li>Common</li>
</ul>
<p>You see: OS X is now displayed as a child entry of the category “Miscellaneous”.
This makes the list much clearer and readable to you, the user of our website.
When you set the argument <code class="highlighter-rouge">hierarchical</code> to <code class="highlighter-rouge">true</code>, the list will look like this (shortened):</p>
<ul>
<li>Categories
<ul>
<li>Software development</li>
<li>Miscellaneous
<ul>
<li>OS X</li>
</ul>
</li>
<li>Common</li>
</ul>
</li>
</ul>
<p>A new level holding just one entry (Categories) appears.
But as we do not want this, you can just unset the title by setting <code class="highlighter-rouge">title_li</code> to <code class="highlighter-rouge">''</code> (an empty string).
The result looks like this:</p>
<ul>
<li>(the empty string)
<ul>
<li>Software development</li>
<li>Miscellaneous
<ul>
<li>OS X</li>
</ul>
</li>
<li>Common</li>
</ul>
</li>
</ul>
<p>Now you can simply style the whole list using CSS.
If you want to see a CSS example, look at the code example below.
We provide you with our CSS styles for our nested category list and with an expert of our functions.php file.</p>
<p>As you can see, it is very easy to manipulate the output of the category widget by just adding a filter to the <code class="highlighter-rouge">widgets_category_args</code> (as shown below).</p>
<p>We hope that this article helps you to understand filters in WordPress and how to change the output of the widgets on the front page.</p>
<script src="https://gist.github.com/b31eeca2d672e3947992.js"> </script>
<script src="https://gist.github.com/456c358f40ea3e2fc109.js"> </script>
Dispatching in CakePHP2012-03-20T00:00:00+00:00http://blog.stekoe.de/2012/03/20/dispatching-in-cakephp<p>Bei intensiver Auseinandersetzung mit CakePHP stellt sich – zumindest mir – nach einiger Zeit die Frage nach dem “wie wird was, wann ausgeführt?”.
Dies ist vor allem dann relevant, wenn man eigene Komponenten, Behavior oder Helper programmiert.
Diesen Vorgang nennt man auch Dispatching des Frameworks.</p>
<p>Im Endeffekt stößt der Besucher einer mit CakePHP entwickelten Seite “nur” ein PHP-Script an, welches dann die Ausführung des Frameworks initiiert.
CakePHP ist in weiten Teilen objekt-orientiert Entwickelt und arbeitet mit verschiedensten Klassen.
Auf ein Objekt-Relationales-Mapping wurde bisher jedoch verzichtet.
Das heißt, dass die Felder einer Datenbanktabelle nicht in Form von Instanzvariablen in einem Objekt bereit gehalten werden, sondern in Form von Arrays.
Die Schlüssel des Arrays entsprechen dann den Feldern in der Datenbank.</p>
<p>Doch zurück zum Dispatching: Oftmals ist es wichtig zu wissen, welche Teile des Frameworks wie aufgerufen werden.
Statt dass man sich die jeweiligen Aufrufe in der Dokumentation heraussucht, habe ich ein kleines Sequenzdiagramm erstellt, welches den Aufruf der wichtigsten Methoden vom Controller, Component und View darstellt.</p>
<!--more-->
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2012-03-20-dispatching-in-cakephp/Dispatching.png" target="_blank" class="image ">
<img src="/assets/images/posts/2012-03-20-dispatching-in-cakephp/Dispatching.png" alt="Image" />
</a>
<figcaption class="figure-caption">Abbildung 1: Dispatching CakePHP</figcaption>
</figure>
CakePHPs MVC-Pattern2012-03-19T00:00:00+00:00http://blog.stekoe.de/2012/03/19/mvc-pattern-cakephp<p>MVC-Pattern sind in aller Munde und bieten eine gute Möglichkeit den logischen Part einer Anwendung von Darstellung und Datenhaltung zu trennen.
Auch das kostenfreie unter der <a href="http://de.wikipedia.org/wiki/MIT-Lizenz" target="_blank">MIT-Lizenz</a> angebotene PHP-Framework <strong>CakePHP</strong> setzt auf das MVC-Muster.
Für unbedarfte Nutzer mag es ein wenig irritierend und fraglich sein, warum die MVC-Splittung im Endeffekt so wichtig ist.
Aber es lohnt sich in den meisten Fällen und es ist nicht schwer die Denkweise zu “erlernen”.</p>
<!--more-->
<p>Die grobe Idee hinter MVC besteht darin Code in logische Segmente zu zerlegen um so Wiederverwendung, Übersichtlichkeit und Aufgabenteilung zu fördern.
MVC ist eine Abkürzung und steht für “Model-View-Controller”, ein eng zusammenarbeitendes, (fast) unzertrennliches Tripple.
Im folgenden werden die einzelnen Akteure etwas genauer beleuchtet:</p>
<h2 id="mvc-pattern-kurz-erklärt">MVC-Pattern kurz erklärt</h2>
<p><strong>Model:</strong> Der überwiegende Teil der Webseiten arbeitet im Hintergrund mit einer Datenbank in welcher alle wichtigen Daten gespeichert werden.
Dies sind Postings, Benutzerdaten, Webseiteninformationen wie Titel, URL, etc. – Um eine Schnittstelle zwischen Datenbank und Webanwendung zu erleichtern, bieten viele Frameworks eine Abstraktion von der jeweilige Datenbank in Form eines Modells an.
Für jede Tabelle in der Datenbank existiert ein Pendant in der jeweiligen Software als Modell, welches alle Felder der Datenbanktabelle enthält.</p>
<p><strong>View:</strong> Die View ist die Repräsentationsschicht des MVC-Patterns.
Sie stellt die an sie übergebenen Daten grafisch in Form einer GUI (Graphical User Interface, Grafische Benutzeroberfläche) dar und ist bei Webanwendungen nichts anderes als ein HTML-Gerüst mit Platzhaltern (Variablen) für den dynamischen Inhalt.</p>
<p><strong>Controller:</strong> Die Daten, Anfragen und Berechnungen (Algorithmen) einer Webanwendung wollen natürlich auch noch berücksichtigt werden und brauchen ihren Platz.
Da Berechnungen nichts mit Datenhaltung zu tun haben, sondern Daten benötigen, gehören sie nicht in das Modell.
Ferner geben Algorithmen nur verarbeitete Daten zurück, sodass sie auch nicht in die View gehören.
Vielmehr wurde eine weitere Zwischenschicht eingeführt, der Controller.
Dieser bezieht seine Daten aus dem Modell (also der Datenbankabstraktionsschicht), verarbeitet diese nach Wünschen des Programmierers und gibt die Ergebnisse an die View weiter um sie anzuzeigen.
Aber auch Eingaben die über die View (in Formularen) getätigt werden, können im Controller abgegriffen und verarbeitet werden.</p>
<h2 id="mvc-in-cakephp">MVC in CakePHP</h2>
<figure class="img-thumbnail " style="">
<a href="/assets/images/posts/2012-03-19-mvc-pattern-cakephp/CakePHP_MVC.png" target="_blank" class="image ">
<img src="/assets/images/posts/2012-03-19-mvc-pattern-cakephp/CakePHP_MVC.png" alt="Image" />
</a>
<figcaption class="figure-caption">Abbildung 1: CakePHP MVC-Pattern</figcaption>
</figure>
<p>Es gibt keine standardisierte Vorgabe wie das MVC-Pattern zu implementieren ist und daher setzen es die verschiedenen Frameworks leicht differierend um.
CakePHP bietet zusätzlich zu den drei Schichten des MVC-Patterns weitere Konzepte an und erweitert damit die Flexibilität und Modularität des Codes.
Im Folgenden werden (analog zur linken Grafik) die wichtigsten Konzepte des MVC-Patterns von CakePHP näher erläutert.</p>
<h3 id="modelle---behavior">Modelle - Behavior</h3>
<p>Behavior sind ein probates Mittel, wenn es darum geht einzelnen Modellen spezielle Eigenschaften oder Funktionsweisen zu implementieren.
Möchte man beispielsweise eine Baumstruktur abspeichern (verschachtelte Listen, Seitennavigation, …), so existiert hierfür ein Tree-Behavior, welches Methoden anbietet die eine Sortierung der verschachtelten Listen (und deren Elemente) ermöglicht und weitere.</p>
<h3 id="views---elemente-und-helper">Views - Elemente und Helper</h3>
<p>Oftmals werden in Views einzelne Teile redundant verwendet.
Wenn eine Tabelle zur Auflistung von Daten an mehreren Stellen benutzt wird, wäre ein naiver Ansatz diese Tabelle via Copy & Paste zu übernehmen.
Sollte jedoch anschließend ein Fehler im Code gefunden werden, muss dieser an allen Stellen geändert werden, an denen die Tabelle auftaucht.
Hier folgt man besser dem DRY-Prinzip: Don’t Repeat Yourself (Wiederhol’ dich nicht!) – CakePHP bietet den Entwicklern die Möglichkeit HTML-Code-Fragmente – wie bspw.
eine Tabelle – auszulagern und an beliebiger Stelle in einer View zu inkludieren.
Diese ausgelagerten Code-Fragmente werden “Element” genannt und können beliebig erstellt werden.</p>
<p>Ferner bietet CakePHP die Verwendung von “Helpern” an.
Heller sind ausgelagerte PHP-Algorithmen, die meist HTML-Code ausgeben.
In CakePHP werden oftmals Formulare nicht händisch, sondern mit Hilfe eines FormHelpers erstellt.
Dieser erzeugt sauberen HTML-Code und kann zusätzlich anhand der ihm übergebenen Daten feststellen, welcher Input-Typ ein Feld besitzen soll.
Helper sind also wesentlich komplexer als Elemente und enthalten meist viel logischen Code.</p>
<h3 id="controller---components">Controller - Components</h3>
<p>Wie bereits in der kurzen Einführung beschrieben verarbeitet der Controller alle Daten einer Anwendung und lenkt diese je nach Verwendung zur View oder in die Datenbank.
Auch dort kann es vorkommen, dass bestimmte Algorithmen mehrfach verwendet werden sollen.
Solange dies in einem Controller geschieht kann die Redundanz über das Auslagern in eine eigenständige Methode verhindert werden.
Sobald jedoch ein Algorithmus in mehreren Controllern verwendet werden soll, kann man diesen entweder in eine Superklasse (AppController) auslagern oder – um die Übersicht zu wahren – eine Komponente schreiben und diese in den jeweiligen Controllern einbinden.</p>
<h3 id="übrige-module">Übrige Module</h3>
<p>Das obige Bild zeigt neben den genannten Modulen weitere Module im unteren Bereich: CakeSession, Cache und Vendors.</p>
<p>Die CakeSession zeigt eindrucksvoll, dass es auch möglich ist über eine Superklasse die gleichen Daten in einer Component sowie einem Helper zu halten.
Die in einer Session gespeicherten Daten sollen sowohl in der View abfragbar sein aber auch im Controller.
Da die Daten konsistent sein müssen, wird hier über eine Superklasse eine gemeinsame Basis geschaffen.</p>
<p>Caching wird im Controller angeboten und ermöglicht es die Last vom Server zu reduzieren.
Im Controller können bestimmte Inhalte in den Cache geschrieben werden.
Jedoch ist auch lesen und löschen möglich.</p>
<p>Vendors sind 3rd-Party Klassen, die nicht speziell für die Verwendung in CakePHP abgestimmt wurden.
Vendors können einfach in jedem Controller inkludiert und verwendet werden.</p>
<h2 id="fazit">Fazit</h2>
<p>Diese kurze Einführung in das MVC-Pattern von CakePHP ist natürlich nicht abschließend.
CakePHP bietet selbst eine sehr umfangreiche und auch gute <a href="http://book.cakephp.org/" target="_blank">Dokumentation</a>.
Durch meine Arbeit mit diesem Framework folgen noch weitere kurze erklärende Beiträge zu diversen Aspekten des Frameworks.
Für heute soll es jedoch an dieser Stelle reichen.</p>
GMF Editor: Bind delete-key to "delete from model" action2011-06-24T00:00:00+00:00http://blog.stekoe.de/2011/06/24/gmf-editor-bind-delete-key-to-delete-from-model-action<p>Im Rahmen meiner Tätigkeit rund um die Entwicklung eines Diagramm-Editors mit Hilfe der Eclipse Framworks EMF, GEF und GMF trat ein Feature-Request auf, welcher nicht leicht zu implementieren ist: Das Löschen von Modellelementen über das Diagramm (allgemein bekannt unter “Delete from Model”) mit Hilfe der Delete-Taste bzw.
der Backspace-Taste.
Die Eclipse-Newsgroups sind voll an Nachfragen zur Umsetzung dieser Problematik.
Das einzige was ausbleibt ist natürlich eine Antwort.
Doch die gibt es jetzt in diesem Artikel.</p>
<!--more-->
<p>Wie in vielen Fällen ist die eigentliche Implementierung weniger kompliziert, als das Finden der richtigen Stelle.
DiagrammEditoren, im speziellen der <tt>org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor</tt>, von welchem die bei uns verwendeten Editoren erben, definieren bereits einige Standard Key-Bindings die man in der eigenen Implementierung überschreiben kann.
Die vordefinierten Bindings sind in der Methode <tt>getKeyHandler()</tt> (<a href="http://publib.boulder.ibm.com/infocenter/rsmhelp/v7r0m0/topic/org.eclipse.gmf.doc/reference/api/runtime/org/eclipse/gmf/runtime/diagram/ui/parts/DiagramEditor.html#getKeyHandler()">Link zur API</a>) definiert.
Zwar kann die Methode nicht direkt überschrieben werden, da diese als protected deklariert ist, aber man kann in der eigenen Implementierung eines Diagramm-Editors (<tt>XXXDiagramEditor extends DiagramEditor</tt>) innerhalb der Methode <tt>configureGraphicalViewer()</tt> auf die bereits defnierten Key-Bindings zugreifen.
Da bei der Initialisierung des <tt>XXXDiagrammEditors</tt> zunächst im Supertyp <tt>DiagramEditor</tt> die Standard Key-Bindings festgelegt werden, können diese abgefragt und manipuliert werden.</p>
<p>Mit den Methoden <tt>getDiagramGraphicalViewer().getKeyHandler()</tt> werden die für den aktuellen Diagramm-Editor registrierten Key-Handler zurückgegeben.
Nun ist es möglich die Key-Bindings zu manipulieren und an eigene Bedürfnisse anzupassen, so dass der Delete-Key eine vom Standard abweichende <tt>IAction</tt> aufruft.
Hier ist ein kleines Code-Beispiel:</p>
<script src="https://gist.github.com/b68dd80e6ec2a0725664.js"> </script>
<p>Dieses Beispiel legt fest, dass die Keys Delete und Backspace die <tt>IAction</tt> “delete from model” aufrufen.
— Im Prinzip war dies auch bereits die gesamte Arbeit, um das Key-Binding von “delete from diagram” auf “delete from model” zu mappen.
Das einzige Problem welches sich an dieser Stelle auftut ist, dass kein Keyboard-Shortcut mehr für die Aktion “delete from diagramm” existiert.
Das löschen von Diagrammelementen funktioniert hingegen jedoch wie gewohnt weiterhin über das Kontextmenü.</p>