Na no na ned – JQuery, Templates und CSS

Hiermit möchte ich eine kleine Reihe starten die sich mit dummen Problemen beschäftigen die mir so im Alltag passieren bzw. die ich verursache und wie ich diese eigentlich offensichtlichen Fehler dann ausbügeln konnte.

Im Folgenden geht es um HTML in Verbindung mit JQuery und CSS. Wie es heutzutage üblich sind, baue ich gerade eine mehr oder weniger monströse App die massiv auf JS angewiesen ist. (Das ist allerdings auch keine Website sondern eine Spotify-App)

Mit JQuery gibt es mehrere Template-Frameworks. In meinem Fall sieht ein Template ca. so aus:

[HTML]

[HTML]

Ich hatte also ein komplexes Template das aus einem DIV bestand, welches in einer Liste floaten sollte. Was ich nicht bedacht hatte: Das verfluchte float zerschießt mir natürlich das restliche Layout das aus lauter absolut und relativ positionierten DIVs bestand.

Lösung? Die wunderWuzi-Klasse floatet jetzt nicht mehr sondern wird als inline-box angezeigt. Problem gelöst.

Android – Wie wird das jetzt “smooth” und so

Wenn man sich mit Android-UI Design beschäftigt, stößt man früher oder später auf Google IO Talks, die sich damit beschäftigen wie eine gute Android App aussehen und sich anfühlen soll.

So wird in diesem Talk davon gesprochen, das eine gute App folgende Eigenschaften haben sollte:

  • Fresh – Apps sollen sich immer auf aktuelle Daten beziehen, sie soll “immer Up to Date” sein.
  • Psychic – Apps sollen die System-Ressourcen und das Android-Framework verwenden um Informationen über den Benutzer zu verwenden um dem Benutzer Arbeit zu ersparen. In solche Kategorien fallen z.B. Scrobbling und Vorschläge bei last.fm, automatisch in den Energiesparmodus nach 22 Uhr etc.
  • Adaptiv – Die App existiert für den Benutzer nur als Kontext in dem er etwas erledigen möchte. Das bedeutet, dass die App niemals schlecht auffallen darf, z.B. wenn viel manuelle Texteingabe verlangt wird oder ähnlich “unmobile” Anforderungen in der UI gestellt werden. Die App soll wie die Unterhose sein: Hübsch wenn man sie sich bewusst anschaut aber im Alltag unsichtbar und bequem.
  • Smooth – Die App soll schnell, flüssig und angenehm bzw. responsive reagieren.

Mit dem letzten Punkt möchte ich mich in diesem kleinen Artikel beschäftigen. Doch zu aller erst die Fragen: Wie werden Anwendungen langsam, zäh und warum frieren sie ein?

Normalerweise werden im onCreate einer Activity-Klasse alle Objekte die während der Lebenszeit der Activity verwendet werden müssen initialisiert.

Das sind zum einen die relativ günstigen findView-Aufrufe und auf der anderen Seiten Objekte wie ListView-Adaptars, EventHandler, Code um auf Server zuzugreifen, Code um auf die SQLite-DB zuzugreifen, etc. Die Manigfaltigkeit der Performance-Fresser ist erschlagend groß.

Dazu kommen noch andere Todfeinde der Android-Smoothness:

  • Der Garbace Collector, ein Erzschurke dessen Durchlauf mitunter 600ms Zeit kosten kann. Man spricht auch davon, dass er die Welt “anhält”.
  • Die versteckten Objektbrüter die den GC in Zugzwang bringen können. (Anonyme Klassen für Event-Handler, foreach-Schleifen die Iterator-Objekte anlegen, etc.)

Doch auf diese Aspekte werde ich im folgenden nicht eingehen, sondern mich auf die onCreate-Problematik stürzen. Zu dem Thema GC und wie man ihn vermeidet sind vor allem Ressourcen zum Thema Spieleentwicklung sehr zu empfehlen. Siehe z.B. (Beginning Android Game Development, Google IO Talks Memory Management, Android Real Time Game Development)

Doch zurück zu onCreate, im folgenden möchte ich ein kleines Framework vorstellen, mit dem ich massive Verzögerungen durch ORMLite -und PageViewer- Instantiierungen schmerzlos gemacht habe.

Dem möchte ich allerdings eine Annahme vorausschicken, und zwar dass es dem Benutzer vollkommen egal ist ob eine Operation 200ms oder 2s dauert, solange die App präsent ist und nicht einfach vor sich hinstockt bis endlich die Activity aufpoppt.

Unter dieser Prämisse sollte klar sein was im onCreate passieren darf:

  1. Die Content-View muss gesetzt werden.
  2. Die View-Referenzen können gesetzt werden. Wie oben bereits geschrieben, sind die Aufrufe relativ günstig und verzögern den Aufbau der Activity auf meinem schwachbrüstigen Wildfire kaum. (Aufpassen: findView-Aufrufe dürfen nicht in andere Threads ausgelagert werden, weil nur der Thread auf die Referenz zugreifen darf, der sie auch hergestellt hat.)
  3. Code anstarten, der die teuren Operationen in einem anderen Thread anstartet.

Schauen wir uns doch einfach ein kleines Code-Beispiel an bei dem es sehr einfach ist die Schnecke zu finden:

public class SlowAppTestActivity extends Activity {
    private ListView lvItems;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        lvItems = (ListView)findViewById(R.id.lvItems);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.item, getItems());
        lvItems.setAdapter(adapter);
    }

    public List<String> getItems() {
    	final ArrayList<String> items = new ArrayList<String>();
    	for(int i = 0; i < 35; i++) {
    		items.add(String.format("Number %d and very useful!", i));

    		// simple code to sleep ...
    		try {
    			Thread.sleep(200);
    		} catch(InterruptedException e) {e.printStackTrace();}
    	}

    	return items;
    }
}

Das zugehörige Layout sieht so aus:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Ready!" />
    <ListView
        android:id="@+id/lvItems"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
</LinearLayout>

Also wenden wir jetzt mit dem AsyncTask aus dem Android-Framework die drei Punkte an. Zu erst setContentView und findView-Aufrufe erledigen. Im nächsten Schritt den Code für die asynchrone Ausführung anstarten und im letzten Schritt, wieder im UI-Thread, die UI updaten.

Mit diesen Anpassungen sieht das onCreate nun so aus:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        lvItems = (ListView)findViewById(R.id.lvItems);

        AsyncTask<Void, Void, ArrayAdapter<String>> task = new AsyncTask<Void, Void, ArrayAdapter<String>>() {

			@Override
			protected ArrayAdapter<String> doInBackground(Void... params) {
				ArrayAdapter<String> adapter = new ArrayAdapter<String>(SlowAppTestActivity.this, R.layout.item, getItems());
				return adapter;
			}

			@Override
			protected void onPostExecute(ArrayAdapter<String> adapter) {
				lvItems.setAdapter(adapter);
			}
		};

		task.execute();
    }

Es steht jedem frei beide Varianten auszuprobieren. Der Unterschied ist enorm. Doch wie kann man diesen Teil sinnvoll abstrahieren um es an mehreren Stellen zu verwenden?

Schauen wir uns, unsere drei Schritte noch einmal an. Der erste Schritt kann genau wie er ist im onCreate bleiben. Hier macht es also keinen Sinn herumzudoktern, dito für den zweiten Schritt. Der dritte Schritt wird schon interessanter, denn es soll etwas asynchron ausgeführt werden.

Im letzten Teil soll wieder etwas synchron im UI-Thread ausgeführt werden. Daraus lassen sich nun zwei Methoden ableiten die wir gleich in ein Interface gießen:

public interface IAsyncWorker {
	public void processAsync();

	public void onAsyncFinish();
}

Jetzt ist klar was passieren soll, aber wer erledigt es? Eine einfache Klasse namens AsyncWorkerLauncher bietet sich dafür an.

public class AsyncWorkerLauncher extends AsyncTask<Void, Void, Void> {
	private final IAsyncWorker worker;

	public static AsyncWorkerLauncher from(IAsyncWorker worker) {
		return new AsyncWorkerLauncher(worker);
	}

	public AsyncWorkerLauncher(IAsyncWorker worker) {
		this.worker = worker;
	}

	@Override
	protected Void doInBackground(Void... params) {
		worker.processAsync();
		return null;
	}

	@Override
	protected void onPostExecute(Void result) {
		worker.onAsyncFinish();
	}
}

Mit diesen paar Zeilen Code kann jetzt unsere Activity umgebaut werden:

public class SlowAppTestActivity extends Activity implements IAsyncWorker{
    private ListView lvItems;

    ArrayAdapter<String> adapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        lvItems = (ListView)findViewById(R.id.lvItems);
        AsyncWorkerLauncher.from(this).execute();
    }

    public List<String> getItems() {
    	final ArrayList<String> items = new ArrayList<String>();
    	for(int i = 0; i < 35; i++) {
    		items.add(String.format("Number %d and very useful!", i));

    		// simple code to sleep ...
    		try {
    			Thread.sleep(200);
    		} catch(InterruptedException e) {e.printStackTrace();}
    	}

    	return items;
    }

	@Override
	public void processAsync() {
		adapter = new ArrayAdapter<String>(SlowAppTestActivity.this, R.layout.item, getItems());
	}

	@Override
	public void onAsyncFinish() {
		lvItems.setAdapter(adapter);
	}
}

Und Bumm: Plötzlich haben wir eine Activity die sich tatsächlich smooth anfühlt und deren Code nicht umständlicher zu lesen ist.

Das Projekt findent man übrigens hier: SlowAppTest.

Werkstatts-Update

Die letzten Monate hatte ich kaum Zeit mich eigenen Projekten zu widmen. Sei es die Universität, der Job oder ganz einfach Sport – welchen ich bitter notwendig habe – der mich vom Codieren und Experimentieren abgehalten haben.

Doch so untriebig war ich dann auch wieder nicht. Seit Oktober 2011 bin ich Programmierer in einem Startup und habe damit die Gefilde der Enterprise-Softwareschmieden verlassen um in die vermeintlich “niederen” Gefilde der Jungunternehmen abzusteigen.

Das tolle daran ist, dass ich jetzt nicht mehr auf JEE oder .Net Enterprise Entwicklung gebunden bin und dementsprechend mit Frameworks arbeiten darf, die auch Spaß machen.

Zu aller erst wäre da Android. Jede Woche arbeite ich mich weiter in dieses Framework hinein, fluche und zürne über Design-Entscheidungen, staune über die Google IO-Präsentationen und hacke Java so viel wie noch nie.

Eines darf ich verraten: Es ist eine Neuentwicklung und ich baue mein Haus auf einer grünen Wiese!

Dazu kommen Javascript bzw. JQuery und HTML5. Up to date, nicht nur in der Freizeit sondern endlich auch beruflich.

Doch um es knackig zusammen zu fassen mit welchen Frameworks ich mich zur Zeit beruflich oder privat beschäftige:

  • Play Framework (Java Web-Entwicklung, die Spaß macht!
  • Android Framework
  • HTML5/Javascript

Doch welche Ideen trage ich mit mir herum die es wert sind umgesetzt zu werden?

  • Haushaltsbuch-App: Die Idee ist schnell erklärt, denn dabei handelt es sich um ein Haushaltsbuch das immer dabei ist. Der Grundgedanke ist alle Ausgaben aufzuzeichnen und zwar dann wenn sie passieren. Bonus: Server-Anwendung mit Play-Framework.
  • Ernährungs- und Trainingstagebuch-App: Wieder eine simple Anwendungen deren Zweck aus meiner eigenen Faulheit kommt. Ich schaffe es einfach nicht mich aufzuraffen und diese Daten am PC einzutragen oder auch nur in ein Büchlein einzutragen. Denn diese Büchlein neigen dazu nie dort zu sein wo ich sie gerade haben möchte.
  • Musikkenner-App: Was soll das sein? Manchmal sitze ich da und browse durch meine MP3-Files und bin absolut unzufrieden. Ich ordne den einzelnen CDs Jahre zu und fühle mich wie jemand, der dumpf in der Vergangenheit wühlt, wenn ich dann doch Musik starte. Also muss neues her! Die Idee: Eine Anwendung schreiben die, die lokale Musikdatenbank scrobbled und dann Vorschläge anhand des vorgefundenen Musikgeschmacks machen. Als nötige Wissensdatenbank könnten dabei Echonest, Yahoo Music oder Musicbrainz herhalten.
  • Ein paar Android-Spiele.

Neben diesen Ideen beschäftige ich mich auch damit, auf java-forum.org hilfreich zur Stelle zu sein um durch auftretende Fragen etwas zu lernen. Stackoverflow gehört hier natürlich auch genannt.

Ghostscript and ps2pdf – A little odyssey

Recently I had to update some 3rd-party software in our server environment. We’re using Ghostscript as weapon of choice for converting PS-files in PDF-files.

As you may know there is a special BAT-file for this purpose in the lib directory of the Ghostscript directory.

If you use the ps2pdf.bat or in a *nix-enviornment the ps2pdf-file there you have to specifiy at least the source- and the destination-file for the command. The command itself writes the parameters in a temp-file in the temp-directory because the authors are frightened to overrun the command buffer in the shell.

This little detail makes it essential for you to correctly set the TEMP and the TMP environment variable. Because if you don’t, you do not know for sure where the variable is pointing to.

In my case I had to figure out why the command did work as a charme when I ran it in a shell but failed when it ran itside a self written Job-Framework.

The log displayed following error message:

Ghostscript 8.60: **** Could not open temporary file ''

and

**** Unable to open the initial device, quitting.

But why did this happen? I don’t know exactly but I think it has to do with the difference between a regular user and a very restricted service-user.
I’m writing this in English because I couldn’t find a good explanation for the problem with ghostscript 8.60. If you search just for ‘Ghostscript **** Could not open temporary file ”’ you’ll get really fast good explanations but sometimes I’m just a blockhead. I hope this short blog article helps somebody.

But after getting the old version running I had to update to version 9.02. Because I use the 64 bit version. I first tried 9.01 but the gswin64c.exe and the gswin64.exe just stopped working with an unexpected error so I switched to the newest version.

But – and that’s a really annoying point – the people from Ghostscript didn’t update the BAT-files. So the environment variables which get set in the gssetgs.bat point to non existing gswin32-exes.

To get this running just change the lines:

if %GS%/==/ set GS=gswin32
if %GSC%/==/ set GSC=gswin32c
if %GS%/==/ set GS=gswin64
if %GSC%/==/ set GSC=gswin64c

And don’t forget to add the needed directories to the path variable when you try to run ps2pdf. In the new version you not only have to add the Ghostscript directories

 %ProgramFiles%\gs\gs9.02\lib
 %ProgramFiles%\gs\gs9.02\bin

You also have to add a directory with a strfind.exe init. In a 64-bit environment that’s:

%windir%\SysWOW64

So to get the new ps2pdf.bat running you have to change the gssetgs.bat file to the following:

@echo off
@rem $Id: gssetgs.bat 6300 2005-12-28 19:56:24Z giles $

rem Set default values for GS (gs with graphics window) and GSC
rem (console mode gs) if the user hasn't set them.

if %GS%/==/ set GS=gswin64
if %GSC%/==/ set GSC=gswin64c

set path=%ProgramFiles%\gs\gs9.02\lib;%ProgramFiles%\gs\gs9.02\bin;%windir%\SysWOW64
set TMP=%YOUR_TEMP%
set TEMP=%TMP%

Rudimentary Stack Environment – Forth ähnliche Skriptsprache

Die Idee

Die letzten Wochen und Monate waren beinahe vollkommen von meinem Studium und meiner neuen Arbeit ausgefüllt. Doch da ich noch immer viele Wege habe, bin ich auf den Fahrten etwas zum Lesen gekommen. Da ich gerade eine Lehrveranstaltung mit dem Thema Stackbasierte Sprachen besuche, habe ich mir auch gleich die PDF-Version von Thinking Forth gekrallt. Dank meines neuen EBook-Readers, lese ich es jetzt sogar.

Dabei kam mir ein altes .Net-Projekt wieder in Sinn: RSE NonForth, eine Skriptsprache deren Prinzip nahtlos an das von Forth anschließt:

  • Kommandos bzw. Words exekutieren Code.
  • Der Interpreter ist dumm und bietet außer der Infrastruktur eines Stacks, Dictionaries – quasi Namespaces – und einer Handvoll Primitives zum Nachladen anderer Bibliotheken überhaupt keine Funktionalität.

Dadurch war es sehr leicht möglich – auch ohne akademische Erfahrung – einen funktionierenden Interpreter zu schreiben. Da ich mich bei meiner neuen Stelle für eine Java-Firma entschieden habe – mir persönlich ist .Net nach wie vor sympathischer aber das Unternehmen war wiederum sympathischer als die .Net-Firmen – werde ich das ganze Ding wohl neu in Java schreiben und schon in der ersten Version die Möglichkeit von Chainlets inkludieren.

Chainlets – WTF?

Die Grundidee von Chainlets fußt auf der Vorstellung von untereinander verknüpfbaren Widgets. Also: Warum kann ich z.B. nicht mein Widget dass mir die Übersicht aller Kalendareinträge präsentiert nicht beibringen, dass es den Termin einem beliebigen anderen Widget per Doppelclick übermittelt?

Ganz einfach darum nicht, da es den Widget-Plattformen die ich kenne, wie z.B. die von Windows oder die Vorschläge von W3C, keine Infrastruktur für solche Aufgaben zur Verfügung stellen. Ich habe dann lang herum überlegt wie diese Schnittstelle zu beliebigen anderen Widgets funktionieren könnte und bin zu dem Schluss gekommen, dass dies am einfachsten in einer Stackgetriebenen Umgebung möglich wäre.

So werden die einzelnen Widgets vollkommen von einander entkoppelt und sie können zusammen arbeiten wie es der Programmierer vorsieht. Er muss die einzelnen Widgets nur untereinander verketten.

Damit war auch gleich die Begrifflichkeit gefunden: Chainlets.

Aber Forth …

Forth hat jetzt natürlich einen Nachteil – jedenfalls für so eine Scripting Engine – ich müsste einiges herumdoktoren damit ich beliebige Objekte auf den Stack legen kann. Natürlich könnte das mit Adressen funktionieren zu denen im Bedarfsfall gesprungen aber im Endeffekt entwickelt sich die Vorstellung zu einer gar grausigen Angelegenheit.

Darum schreibe ich einen Interpreter dessen Syntax der von Forth ähnlich ist und deren Philosophie sowie Handling einiges an Ähnlichkeiten aufweist aber dennoch etwas ganz anderes ist.

Jedem der an dieser Stelle keine Ahnung hat wovon ich hier schreibe lege ich folgende zwei Lektüren ans Herz:

  • Starting Forth – Eine Einführung die dem interessierten Programmierer eine neue Art des Denkens mithilfe von Forth zeigt.
  • Thinking Forth – Ein Buch über das (Kunst-)Handwerk Software Entwicklung mit Forth. (Sehr interessant da hier sehr schön gezeigt wird, dass iterative Modelle wie Scrum schon in den 80ern existierten und von Forth-Codern angewandt wurden.)

Der Aufbau

Ganz grob u. simpel aufgezeichnet wird das System so aussehen:

Dabei sticht ins Auge, dass eine Unterscheidung zwischen Word u. einem so genannten System Word existiert. Der Unterschied ist schnell erklärt: Da in diesem System alle Words immediate sind, wird das Word sobald es in der Queue selektiert wird ausgeführt.

Von dort aus kann es dann aber noch weiter Einfluss auf den Programmfluss nehmen. Ein gutes Beispiel dafür ist z.B. ein IF oder eine Schleife wie +LOOP. Ein IF muss z.B. wissen welche nachfolgenden Words in den eigenen Bereich fallen. Dazu benötigt es mehr Zugriff auf das System also nur den Daten-Stack.

Da aber nicht alle Word so einen Zugriff auf das System benötigen, wie z.B. DUP oder DROP, existieren auch explizit Words die nur Zugriff auf den Stack haben.

Das Diagramm ist schön u. gut aber wie sieht der Ablauf aus?

Soweit so gut. Nun ist es wohl an der Zeit mit dem Schwafeln aufzuhören und mit dem Coden anzufangen.

Picknick – Seltsamer explode-Bug

Die letzten Tage versuche ich Picknick tatsächlich produktiv für ein kleines privates Projekt einzusetzen. Was mir sauer aufstößt sind plötzlich Bugs die ich auf meinem Windows-Entwicklungssystem nicht hatte.

Dabei geht es zum einen um die übliche Problematik die nicht bedacht wurde und ganz sauber auf die OS-API zurückzuführen sind. Also z.B. bei Dateinamenvergleiche prüft Windows – jedenfalls nicht Windows 7 – nicht auf gleiche Großkleinschreibung, Linux schon. Natürlich vollkommen dämlich und meine Schuld.

Doch dann ein Bug in PHP selbst der wieder nur in Linux auftritt. Die Funktion explode lieferte – ohne ersichtlichen Grund – Nullwerte im resultierenden Array. Was zum Teufel?  Zu aller erst dachte ich, ich wäre der einzige der diesen Fehler “gefunden” hat und darunter leidet doch dann fand ich diesen Eintrag.

Dort wurde das ganze auf doppelte Leerzeichen zurückgeführt die bei mir nicht auftraten da ich anhand eines “/” trenne. Was also tun? Zum einen hätte ich mit Regex drüberfahren können, doch die Implementation von Regex gefällt mir in PHP nicht weswegen ich zu einer simplen For-Schleife mit einer darin enthaltenen If-Abfrage gegriffen habe.

    /**
     * Calls explode with '/' as delimiter on $url and removes every empty
     * string in the resulting array and returns this array.
     * @param string $url
     * @return array(string)
     */
    private function GetUrlParts($url) {
        // I had to use this because on a free linux webserver explode didn't
        // work properly and returned empty fields in the array which lead to
        // errors
        $nonFilteredParts = explode('/', $url);
        $filteredParts = array();
        $filteredIndex = 0;

        for($i = 0; $i < count($nonFilteredParts); $i++) {
            $element = $nonFilteredParts[$i];

            if(strlen($element) > 0) {
                $filteredParts[$filteredIndex] = $element;
                $filteredIndex++;
            }
        }

        return $filteredParts;
    }

Anstatt explode(‘/’, $var) wird nun oben genannte Methode aufgerufen. Funktioniert nun, ist auch schon im Git-Repo eingechecked.

Picknick – Mit Page-Authentification

Die Basisarchitektur von Picknick hat keinerlei Authentifizierungsmöglichkeiten. Das macht natürlich einen schlechten Eindruck in Zeiten in denen darüber diskutiert wird wie dem Benutzer klar gemacht werden kann, dass es lohnt den Registrierungsaufwand auf sich zu nehmen.

Wie bereits im ersten Post angekündigt ist Picknick mit strengen Blick auf OOP-Pattern entwickelt worden. Da ich mich zur Zeit noch einfinde in der Welt der schwach typisierten Sprachen entwickle ich noch immer so als wäre es .Net 1.1 und nicht PHP.

Also, wie kann ich meine Pages authentifizierbar machen? Meine Idee, ganz nach dem Prinzip “Has-A is better then Is-A” wird das Authentifizerungsmodul ausgelagert. Dafür habe ich in etc einen Ordner namens “authentication” angelegt. Da, meiner Meinung nach, ein Authentifizerungsmodul nur zwei Funktionen hat:

  • Authentifizerungsdaten aufnehmen
  • Prüfen ob diese zu einer validen Authentifizerung führen.

Dementsprechend sieht auch das Interface aus, welches ich geschrieben habe:

<?php
/**
 * A basic interface which is open to all kind of authentication methods.
 */
interface IAuthenticatable {
    /**
     * Sets the credentials of the authenticatable module with the given array.
     * @param array(mixed) $credentials The credentials as array.
     * @return void
     */
    function SetCredentials($credentials);

    /**
     * Checks the given credentials and returns an boolean value indicating
     * wether the authentication was successful or not.
     * @return boolean
     */
    function Authenticate();
}
?>

Das ist auch schon alles. Natürlich stellt sich jetzt die Frage wie das ganze verwendet werden kann. Dafür muss der zeitliche Ablauf Der zeitliche Ablauf des Frameworks läuft sehr simpel ab:

  1. Kernel wird instanziert. Dieser Schritt lädt alle Klassen, generiert aus dessen Filenamen die Klassennamen und instanziert diese. In diesem Schritt wurde noch kein HTML-Code ausgegeben weswegen auch die header-Funktionen verwendet werden kann. Als letzter Schritt wird die Initialize-Methode der Page aufgerufen. Dies ist die Vorbereitung für den zweiten Schritt.
  2. Der Kernel ruft in ShowPage die ShowBody-Methode der zur zeit gesetzten Page auf.

Das heißt der letzte Schritt des Instanzierens kann auch dazu genutzt werden die aktuell gesetzte Page des Kernels auf eine andere zu setzen. Soll das heißen, dass eine Page einer anderen den Vorzug geben kann? Ja, genau das. Eine jede Page bekommt bei ihrer Instanzierung die Referenz auf den Kernel mit und kann so ganz einfach während der Page-Lebenszeit deren Methoden aufrufen.

Um das ganze zu automatisieren, werde ich eine Klasse schreiben, die genau diese Abläufe automatisiert. Ein Teil davon, ist das Extrahieren der Daten die für die Authentifizierung relevant sind. (Stichwort: Data Sinks, Data Provider) Die folgende Klasse erledigt alle Prozesse die für eine solche Infrastruktur nötig sind, bis auf folgende:

  1. Es wird die “Flucht”-Page bzw. die Bailout-Page nicht gesetzt. Das heißt, das muss in der vererbten Klasse gemacht werden.
  2. Es wird das AuthModul nicht gesetzt. Auch das muss entweder in der abgeleiteten Klasse oder durch Code-Änderungen im Kernel geschehen.
  3. Die nötigen Credentials für das AuthModul werden nicht geladen. Dafür muss die abstrakte Methode in den Kindsklassen mit Leben gefüllt werden.
<?php

require_once(dirname(__FILE__) . '/../../core/main.inc.php');

/**
 * This class handles the functions which are needed to process an authentication
 * for the given page.
 */
abstract class AuthPage extends Page {
  /**
   * Contains the authenticatable module
   * @var IAuthenticatable The authenticatable module
   */
  protected $AuthenticationModule;

  /**
   * Contains the bailout page. This page is set as current page in the kernel
   * if the authenticatable module is null or the returns false.
   * @var Page The bailout page.
   */
  protected $BailoutPage;

  /**
   * Initializes the host.
   */
  public function __construct($host) {
      parent::__construct($host);
      $this->BailoutPage = null;
      $this->AuthenticationModule = null;
  }

  /**
   * Sets the auth module for this class. $module must be of the type IAuthenticatable.
   * @param IAuthenticatable The authenticatable module
   * @return void
   */
  public function SetAuthModule($module) {
      if(!($module instanceof IAuthenticatable))
          throw new WrongTypeException("The authenticatable module must be of the type IAuthenticatable!");

      $this->AuthenticationModule = $module;
  }

  /**
   * Initializes the auth module and authenticate the current user. If the
   * data isn't valid it invokes the bailout page.
   */
  public function Initialize() {
    $page = $this->GetBailoutPage();

    if($this->AuthenticationModule == null) {
        $this->Host->InvokePage($page);
    }
    else {
        $this->AuthenticationModule->SetCredentials($this->GetAuthModuleCredentials());

        if($this->AuthenticationModule->Authenticate()) {
            /* nothing do here - the user is authenticated for this page */
        }
        else {
            $this->Host->InvokePage($page);
        }
    }
  }

  /**
   * Returns the bailout page. If BailoutPage is null it returns the standard page.
   * @return Page
   */
  private function GetBailoutPage() {
      if($this->BailoutPage == null) {
          return new Standard();
      }

      return $this->BailoutPage;
  }

  /**
   * This method is for initializing the auth module. Just grab the data you need
   * for it and return it.
   * @return array(mixed)
   */
  public abstract function GetAuthModuleCredentials();

  /**
   * Gets the current set authenticatable module.
   * @return IAuthenticatable
   */
  public function GetAuthModule() { return $this->AuthenticationModule; }
}

?>

Picknick – ein PHP-Framework

Vor kurzem habe ich damit angefangen ein kleines PHP-Framework zu schreiben. Der Grund dafür war, dass ich für einen Freund eine Anwendung entwickeln soll die es ihm ermöglicht Downloads anzubieten und diese an PINs zu koppeln um verfolgen zu können wie viel Erfolg die jeweilige Flyer-Kampagne in bestimmten Orten hatte.

Nachdem ich einen sehr simplen Prototypen entwickelt hatte, unzählige PHP-Files und Ärger mit den Abhängigkeiten sowie ein wildes Mischmasch aus HTML und PHP hatte, wollte ich wieder in das Entwickeln mit PHP reinkommen. Da ich aus der .Net-Welt stamme, machte ich mich gleich daran ein PHP-Framework für kleine bis mittelgroße Projekte zu entwickeln dass vor allem auf zwei Prinzipien aufbaut:

  1. Es soll natürlich eine saubere OOP-Architektur sein.
  2. Es soll ohne PEAR auskommen und sofort auf einem xampp light Server laufen können.

Nach drei Wochen Entwicklungszeit war es so weit: Die oben genannten Punkte sind erreicht und jetzt geht es an die Arbeit um das oben genannte Projekt endlich ernsthaft umzusetzen. DB-Design ist schon fertig und ein grobes Framework für den Seitenaufbau auch. Nun geht es an die Arbeit. Doch wie funktioniert das mit Picknick?

Das Framework ist kann ganz einfach über meinen Account auf github zu holen, entweder in dem man den Letztstand bei den Downloads runterlädt (Achtung: nicht auf dem neusten Stand) oder in dem man mit git arbeitet. (Ich arbeite mit msysgit auf Windows)

cd projectdir
git clone git://github.com/schlingel/picknick

Danach hat man auch schon einen Ordner in seinem projectdir namens picknick mit allen nötigen Dateien. Danach kann man die Dateien aus dem picknick Ordner nach projectdir verschieben. Nun kann die Entwicklung los gehen. Ab Werk kommt das Framework mit einer Fehlkonfiguration da ich einmal vergessen habe git rm auszuführen. Dass kann man schnell ändern indem man die Konsole bemüht:

cd projectdir
cd etc/html.helper/
git rm SlashedLinkHelper.php
git rm DefaultLinkHelper.php.unused
git rm LinkHelperTags.php

Nun kann es auch schon mit der persönlichen Entwicklung losgehen. Als Ausgangsdatei – um im Picknick Technikus Terminus zu bleiben – bzw. dem Kernel-File sieht der Benutzer folgendes in der index.php:

<?php

include './core/main.inc.php';

$kernel = new Kernel();

?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
        <title><?php echo $kernel->GetTitle(); ?></title>
    </head>
    <body>
        <?php
            $kernel->ShowPage();
        ?>
    </body>
</html>

Sofort ist ersichtlich, dass es nur eine zentrale Include-Datei gibt: main.inc.php. Dieses File muss eingebunden werden. Sobald dies eingebunden ist, ist auch jedes PHP-File im Projekt eingebunden. Bis auf die vier Zeilen PHP-Code ist sonst alles valides HTML und so sollte es auch bleiben. Das heißt, innerhalb eines Kernel-Files sollten nur Änderungen am HTML-Code gemacht werden.

Was passiert hier eigentlich? Der Knackpunkt ist der Konstruktor des Kernels. Dieser initialisiert das Skript und lädt die anzuzeigende Page. Falls keine gesetzt wurde, wird die Standard-Page verwendet die immer existieren muss! Der Konstruktor tut folgendes:

    public function  __construct() {
        $this->Logger = new LoggingPublisher();
        $this->DataAccessor = new DataAccessor();
        $this->HtmlWriter = new HtmlWriter();

        $this->Initialize();
    }

Wobei hier vor allem die Initialize-Methode von Interesse ist:

    /**
     * Initializes the parts of the Kernel which are used in every call.
     */
    private function Initialize() {
        $this->GetLoggerFromEtc();
        $this->GetDataProviderFromEtc();
        $this->GetDataSinkFromEtc();
        $this->GetHtmlHelperFromEtc();

        $this->DataAccessor->Initialize();
        $this->HtmlWriter->Initialize($this->DataAccessor->GetAssocArray());

        $this->InvokePage($this->GetPage($this->GetLocationLink()));
    }

Die DataAccessor-Klasse dient dazu die so genannten Data Sinks und Data Provider zu bündeln. Eine Data Sink ist eine Klasse die sich um das Verarbeiten von bestimmten Parametern kümmert. (Z.B.: POST-Parameter oder die in die URL verpackten Daten.) Ein Data Provider kümmert sich darüber hinaus auch um das Weitergeben von Daten von Klick zu Klick. D.h. er persistiert die Daten für die gesammte Browser-Session. Der Parameter der bestimmt welche Seite geladen werden soll heißt “location”.

Doch wie entwickle ich nun eine solche Seite? (Technikus Terminus: Page) Dazu müssen nur folgende einfache Schritte befolgt werden:

  1. Das main.inc.php File anpassen. Hier für das Define __PROJECT__ den Projektordner in htdocs eintragen. Z.B.: projectdir
  2. PHP-File im page-Ordner erzeugen z.B. mit dem Namen NewPage.php
  3. Innerhalb des Files die Haupt-Include-Datei einbinden. Am besten mit folgendem Code:
    require_once dirname(__FILE__) . '/../core/main.inc.php';
  4. Eine Klasse mit dem selben Namen wie das File (in diesem Fall NewPage) erzeugen die von Page erbt.
  5. Die GetTitle(), Initialize() und die ShowBody() Methoden erzeugen.

Z.B.: folgender Code:

require_once dirname(__FILE__) . '/../core/main.inc.php';

class NewPage extends Page {
    public function  GetTitle() { return "Eine neue Seite!"; }

    public function  ShowBody() {
        $this->GetLink("NewPage", "Selbstreferenz");
    }

    public function Initialize() { }
}

Diese kurze Seite erzeugt eine Seite mit einem Link auf sich selbst der Selbstreferenz heißt. Wie kann diese Seite nun eingebunden werden? Nachdem der Webserver läuft sieht man, sobald man die Projekt-Page ansteuert, eine hübsche ASCII-Art die das Logo des Projekts darstellt mit einem Link zu “Home”. Möchte man nun seine neue Page erreichbar machen muss einfach nur im Navigations-Template in templates/navigation das links.php File angepasst werden:

<ul style="display: table-row;">
    <li><?php $this->WriteLink('standard', 'Home'); ?> </li>
    <li><?php $this->WriteLink('newpage', 'New Page'); ?></li>
</ul>

Fertig! Nun ist die neue page erreichbar. Dass newpage kleingeschrieben wird ist wichtig! Doch wie komme ich von Newpage wieder zurück nach Home? Dafür muss einfach nur in ShowBody das Template eingebunden werden:

    public function  ShowBody() {
        $this->GetTemplate('navigation/links');
        $this->WriteLink("newpage", "Selbstreferenz");
    }

Voila: Das gewollte ist erreicht. Das nächste Mal werde ich etwas weiter ins Detail gehen, was das ganze System bringt außer einer vorgeschriebenen Ordner-Struktur und einem Include-Management.

Reflexion: ViennaJS-Treffen (25.08.2010)

Wie angekündigt habe ich mir das vienna.js Usergroup-Treffen angesehen. Die Treffen dort waren im Stil von Lightning-Talks gehalten. Daher konnte jeder der wollte, auch wenn er unangekündigt dazu kam, einen kurzen Vortrag halten und dann sich den Fragen des interessierten Publikums stellen. Angekündigt war im Vorfeld nur ein einziger Beitrag, am Ende wurden es dann drei:

  • node.js in the real world
  • JS1k-Democontestpräsentation
  • Objektidentitäten in JS erstellen

Die Vorträge waren unkompliziert und nicht förmlich. Doch was konnte ich tatsächlich aus den Vorträgen für mich an Information mitnehmen?

Zum Thema node.js waren es ein begeisterter wenn auch ernüchtender Erfahrungsbericht:

  • node ist noch weit davon entfernt fertig zu sein. Ständig kommen neue Versionen heraus. Diese Flexibilität führt zwar auf der einen Seite dazu, dass entdeckte Fehler sofort vom Autoren ausgebessert werden aber es von Version zu Version zu Änderungen an der API kommen kann. Daher kann man mit Fug und Recht behaupten zur Zeit ist die API unstable. (Soll sich mit Version 1.2 von node ändern!)
  • Es gibt keine Möglichkeit die eigene node-Anwendung zu testen da es keine (funktionierenden) Testing-Frameworks gibt. Es gibt zwar einige auf Github aber der Vortragende erwähnte, dass er keines davon zum laufen bringen konnte. (Wahrscheinlich verhindern irgendwelche API-Änderungen das Funktionieren)
  • nodes selbst hat noch Bugs. Da der Autor seine Anwendung anscheinend auch nicht testet wohnen der App noch seltsame Fehler inne. (Der Vortragende lieferte drei Beispiele: Zum einen war es ihm nicht möglich Binärdaten in seiner Hash-Funktion zu verwenden. Er musste dafür die Daten in einen String und diesen dann wieder in Binärdaten umwandeln. Das andere – erschreckende – Beispiel: Seine Anwendung funktioniert zwar aber sie stürzt hin und wieder einfach ab bzw. der Server beendet sich einfach. Das letzte Beispiel war eine Inkompatibilität auf Linux: Während auf dem Dev-Rechner – einem Apple – alles problemlos lief, wurden am Testsystem (ein Debian-Linuxserver) die TCP-Verbindungen nicht mehr geschlossen. Dies führte zu kryptischen “File”-Fehlermeldungen.)
  • Monitoring ist zwingend notwendig und durch die Unsicherheit sollte irgend ein Server (lighttp oder ähnliches) dem nodes Programm vorgeschalten sein.
  • Der Quellcode schrumpft durch die asynchrone Architektur für asynchrone Anwendungen auf ein Minimum zusammen und das ganze bleibt dabei sogar lesbar.

Der zweite Beitrag stellte kurz einen Javascript-Contest vor. Interessant ist dabei, dass auf der Projekthomepage die bereits eingereichten Beiträge samt Quellcode eingesehen werden können.

Der dritte Beitrag beschränkte sich auf eine kurze Zusammenfassung was eine Objektidentität ist und das Problem, dass der “===” Operator in JS nicht existiert. Als Lösung stellte der Vortragende eine Funktion vor, die eine statische Variable enthält die ständig hochgezählt wird und so an Objekte IDs verteilen kann. Im Endeffekt konnten dann die Objekte mit Obj1.ID == Obj2.ID auf Gleichheit untersucht werden.

Alles in Allem zwar interessant aber nicht ganz so informativ wie erhofft.

Windows und node.js?

Als (etwas verspätete) Vorbereitung für das Wiener Javascript-Usergrouptreffen im Metalab habe ich angefangen mich mit node.js zu beschäftigen. Was ist das überhaupt? node.js ist eine serverseitige Implementation von Javascript. Jedoch ist das ganze nicht als bloßer JS-Interpreter aufgebaut der mit ein paar netten Libs ausgestattet wurde, es handelt sich dabei um ein eigenes Konzept:

Ein Event gesteuerter Applikationsfluss der auf der V8 Javascript Engine fußt um genügend Geschwindigkeit zu bieten. Ich habe diese Idee folgendermaßen grob umrissen: Die einzelnen Aufgabe die in das Programm eingegliedert werden sind so genannte Nodes die gleichzeitig abgearbeitet werden. Wird eine Node fertig, so feuert diese einen “Finish”-Event worauf das Programm darauf reagiert. Während dieser Event für die Node abgearbeitet wird, kann keine andere Node mit ihrem Finish-Node dazwischenfunken. Das heißt, hier handelt es sich auch automatisch um eine Steuerung der Prozesse.

Welchen Vorteil habe ich nun im Gegensatz zu etablierten Skriptsprachen wie Python, PHP oder Ruby? Argumente die ich gelesen habe, gehen da vor allem auf die Geschwindigkeit ein. Diese bezieht sich auf die Gleichzeitigkeit, nicht auf die Antwortzeit der Skripte. Aus diesem Grund eignet sich node.js wohl mehr für verteilte Anwendungen im einen Netzwerk. Doch wie sieht so ein Server in node.js JS aus?

Ich habe ein altes Beispiel aus diesem Blogeintrag in die neue Syntax übergeführt und war von dem Ergebnis begeistert:

var sys = require('sys'),
  http = require('http');

http.createServer(function(req, res) {
  res.writeHeader(200, {'Content-Type': 'text/html'});
  res.write('<h1>Hello World</h1>');
  res.finish();
}).listen(8080);

Wie kann eine solche Technologie effektiv in der Praxis genutzt werden? So ganz bin ich mir da auch noch nicht sicher, weswegen ich schon sehr gespannt bin auf die morgige Sitzung der Wiener Javascript-Usergroup.

Doch zur eigentlichen Frage: Wie bekommt man node.js auf einem Windows-System zu laufen? Ich habe es mit zwei Möglichkeiten probiert:

  1. Cygwin
  2. VM mit Ubuntu

Eines vorweg: Cygwin hat für mich nicht funktioniert. Als erstes installierte ich Cygwin mit allen zur Verfügung stehenden Developing-Tools. Zu meinem Pech, war dann aber g++ nicht installiert. Das bemerkte ich natürlich erst nachdem ich die Konsole – die ich so nie verwenden werde – installiert hatte.

Der Fehler äußert sich darin, dass das Config-Skript des node.js-Tarfiles sich mukiert weder einen C noch einen C++ Compiler zu finden. Da ich nicht weiß, wie ich in Cygwin-Pakete nachinstalliere ohne das Setup erneut auszuführen bin ich sofort auf eine VM ausgewichen.

Gesagt getan. gcc ist vorhanden (so wie er auch bei Cygwin vorhanden war) und ich starte das config-skript. Wieder scheitert das Skript und schreibt aus, es finde keinen C und keinen C++ Compiler. Etwas verwundert habe ich geschwind den g++ nachinstalliert.

Danach ist ./Configuration erfolgreich durchgelaufen. Dann ein make, welches etwas dauert da auch die V8-Engine gebuildet wird, um darauf mit make install das Programm auch zu installieren. Das lief alles gut durch und danach stand mir node als Kommando zur Verfügung.

Es ist natürlich enttäuschend, dass es noch keine echte Win32-Implementation gibt aber vielleicht kommt diese sobald der Interpreter etwas mehr Aufmerksamkeit bekommt.