Montag, 26. Januar 2009

Unser Projekt in Zahlen und Schlagworten

Eine Woche ist unser Projekt nun schon alt, und damit wohl auch wieder großteils in Vergessenheit geraten. Das Design ist übrigens natürlich überhaupt nicht geklaut, sondern wahrt nur die Corporate Identity!

Abschließend folgt noch eine kleine Statstik über die Verteilung der LOCs in den einzelnen Paketen:

PaketFunktionalitätLOC



ActionAnwendungsfälle (15 Stück!)490
ModelPlain PHP Objects (Attribute, getter, setter)320
Framework
560

Persistenz(230)

Presenter(120)

Controller(90)

Session Verwaltung (Authentication, Identity, Session)(120)
ViewHTML Seiten800



Summe
2170


Im Vergleich mit P3 und P5 sieht man sehr schön, dass die geplante Architektur eingehalten werden konnte und somit eine schöne Kapselung von Zuständigkeiten vorliegt.

Wer sich unser Projekt genauer ansieht, wird beispielsweise feststellen dass wir trotz Datenbank keine vordefinierten SQL Statements verwenden (ORM sei Dank :)). Den Source findet ihr als ZIP hier.

Hier ein paar inhaltsleere Schlagwörter (sinngemäß © Review-Partnerteam), die unser Projekt auszeichnen.
  • URL Rewriting
  • Front Controller
  • SQLLite DB
  • Objektrelationales Mapping (ORM)
  • Templatesystem mit Push und Pull - Ansatz
  • Intensive Singleton Verwendung
  • (Pseudo) Dependency Injection durch Abruf der Singleton Instanzen im Konstruktor der abhängigen Klassen und Referenzierung in privaten Klassenattributen.
  • Interfaces (Klasse Persistence), Abstrakte Basisklassen
  • Class Hints
  • Magische __get() Methoden (zB zur Auflösung von ForeignKeys in Objekte im Rahmen der ORM)
  • Reflection (zb beim Bau der SQL - Statements)
  • AJAX Anzeige freier Plätze (zwecks besserer Vorführbarkeit alle 2 Sekunden randomisiert zwischen 1 und 400)
Durch das mächtige Framework und die Abstrahierung kann sehr einfach produktiv an der Implementierung der Anwendungsfälle (Businees-Logik) gearbeitet werden.

Meine Teamkollegen hat es gefreut, umso mehr da sie zu Beginn des Semesters noch gar keine Ahnung von PHP hatten und durch Zurückgreifen auf bereitgestellte Kernfunktionalität nicht mit Low-Level-Implementierungsdetails überfordert wurden.

Freitag, 16. Januar 2009

WSDL: Eine Nachbetrachtung

Alle Jahre wieder gibt es neue Blogeinträge so wie hier dieser. Fast vier Wochen ist es her, dass ich vom Almighty Webservice Client berichtet habe, und jetzt ist es Zeit für neue Meldungen.

Während kurz vor der Deadline noch alles wunderbar funktioniert hat, meldete sich der Client in den frühen Morgenstunden und am Vormittag darauf mit einem Error. Grund dafür war, dass einige Kollegen ihre fehlerhaften Webservices offenbar gelöscht haben, sodass SoapClient nur einen HTTP 404 Fehler anstatt einer brauchbaren Description XML vorfinden konnte. Da diese Möglichkeit im Client schlicht und einfach nicht berücksichtigt wurde, verwundert das Verhalten auch nicht weiter. Inzwischen ist die Liste der Webservices zwar geschrumpft, dafür aber auch wieder fehlerlos.

Gegen Ende des letzten Jahres hatte ich dann noch die Idee, man könnte doch auch einen generischen Server erstellen. Das klingt zuallererst einmal total verrückt, und ich distanziere mich auch hohoffiziell von jeglicher gedanklicher Inbeziehungstellung mit Sekt oder dergleichem. Technisch ist das aber durchaus machbar.

Wie wir inzwischen wissen sollten, erfolgt die Zuordnung zu einer Klasse zB mit $server->setClass("MissWorld"), die Operationen anhand ihres Namens in Methodenaufrufe übersetzt. Wenn die Operation also "schaffeWeltfrieden" heißt dann wird vom SoapServer Proxy die $missWorldInstance->schaffeWeltfrieden(); Implementierung aufgerufen.

Aber... da müsste man doch die Klasse mit allen je möglichen Operationen/Methoden ausstatten, und das geht ja gar nicht !? Klar, das müsste man, und das kann man mit Hilfe einer magischen Methode (ja, die heißt wirklich auch offiziell so!) machen, nämlich __call():

"__call() is triggered when invoking inaccessible methods in an object context."
http://us.php.net/manual/en/language.oop5.magic.php
Mit Hilfe der aus dem Almighty Client bekannten Parserei schauen wir dann nach, wie der retournierte Typ aussehen muss (primitiver Wert bzw. ComplexType). Die Generierung der Daten erfolgt dann entweder randomisiert oder durch Wiederverwendung der Eingabedaten.

Die Server Klasse könnte dann ungefähr folgendermaßen aussehen, wobei hier davon ausgegangen wird, dass die Argumente primitive Typen und keine Arrays sind, und dass der Rückgabewert ein nicht verschachtelter ComplexType mit primitiven Attributen ist:

class AlmightyServer
{
public function
__call($name, $arguments)
{
$object = WsdlParser::getReturnObjectFor($name);
foreach(get_object_vars($object) as $key=>$value)
{
$object->$key = $arguments[ rand( 0,count($arguments) ) ];
}
return $object;
}
}


Daraus ist aber dann nichts geworden, unter anderem weil das Teamprojekt gerufen hat. Aber davon erst am Wochenende mehr.

Dienstag, 23. Dezember 2008

Sonntag, 21. Dezember 2008

Freaky Friday - A6: Almighty Webservice Client

Ein paar abendliche Punsch können erstaunliche Auswirkungen auf die Kreativität des menschlichen Gehirns haben - so geschehen Freitag abend, als auf der Heimfahrt in der U-Bahn die Idee geboren wurde, einen universellen Webservice Client zu erschaffen.

Die Idee hat sich hartnäckig gehalten und so sind Skripte und Quellen unter http://almighty.pri.univie.ac.at/~aXXXXXXX/a6/client/ zu finden - die Matrikelnummer bitte wieder selbst aus der Teilnehmerliste kopieren.

Ein paar der interessanten Features sind:
  • Komplett automatisiert (Nur WS Name / Ersteller / WSDL URL sind manuell erfasst)
  • Formulargenerierung inkl. Labels
  • Geparster Methodenname als Formulartitel (erkennt "get", "add", CamelCase)
  • Unterstützung komplexer Typen, auch verschachtelt
  • Unterstützung von Arrays als Input Parameter (immer 3 Elemente)
  • Tracelog (Per JavaScript Ein/Ausblendbar)
  • Retournierte Arrays werden als Listen ausgegeben
  • Retournierte Objekte werden als Tabelle ausgegeben (Attributname und Wert)
Sehr viel Magie ist leider nicht dabei, hauptsächlich besteht die Arbeit aus stupidem (quick and dirty) Parsen. Mit ein paar gescheiten Regex wäre das ganze kürzer geworden, aber hauptsächlich ging es mir darum just for fun einen Prototypen zu erstellen. Interessant sind:
  • Reflection für die Objekte: get_object_vars($result); in response.php
  • Method Invocation für den SOAP Client: call_user_func_array( array($this->client,$operation) , $arguments); in definitions.php
Die Anzahl der Server, die damit kompatibel sind ist zwar erschreckend gering, das liegt allerdings an Fehlern in deren Implementierung - Feedback ist in der Auswahlliste zu finden.

Montag, 8. Dezember 2008

A6: Webservice Server Release

Das zuvor beschriebene Arzneimittel-Codex Webservice ist nun fertig implementiert, hier gibt es die Details.

Operation 1: String[] getArzneimittelliste(String stoffklasse)
Operation 2: Medikament getMedikament(String handelsname)

Der komplexe Datentyp Medikament enthält (in dieser Reihenfolge) die String-Elemente handelsname, freiname, wirkstoff, indikationen, kontraindikationen

Folgende Arzneimittelklassen sind vorhanden: Antibiotika, Antihistaminika, Benzodiazepine, Sonstiges. Je nach Kategorie werden dabei zwischen 1 und 3 Medikamente (Array Elemente) gespeichert. Wird eine "unbekannte" Arzneimittelklasse angefordert, so werden immer die Allheilmittel Panazee und Theriak zurückgeliefert.

Mögliche Medikamente sind Fenistil, Floxapen, Invanz, Ospamox, Panazee, Psychopax, Theriak und Valium. Zu diesen 8 Medikamenten können mit Operation 2 auch Details abgerufen werden. Bei einem unbekannten Medikament sind alle Attribute des zurückgelieferten Objekts NULL-Werte.

Wer bereits den Client implementieren will, dem kann ich versprechen dass ich keine Änderungen mehr geplant habe. WSDL und Server Source befinden sich am Almighty (http://almighty.pri.univie.ac.at/~aXXXXXXX/a6/). Interessenten mögen die Matrikelnummer in der Teilnehmerliste der Übungsumgebung nachschlagen, da ich sie hier nicht gleich Google direkt in den Rachen werfen möchte.

Sonntag, 7. Dezember 2008

A6: Webservice Server Preview

Meine aktuelle Idee zu dieser Aufgabe kommt einmal mehr aus dem Bereich der medizinischen Informatik.

Operation 1 erhält als Parameter eine Arzneimittelklasse, und retourniert ein Array von Präparaten (Handelsnamen). Eine Liste dazu gibt es unter http://www.meduniwien.ac.at/medtools/medlist/ind-list.pdf, ein Teil davon wird wohl per Copy und Paste Einzug in mein Webservice erhalten.

Operation 2 realisiert einen Arzneimittelkodex (In Österreich: "Austria Codex"). Als Parameter wird der Handelsname eines Präparats als String übergeben, der komplexe Datentyp "Medikament" mit detailierten Informationen (Freiname, Wirkstoff, Indikationen, Kontraindikationen) zurückgegeben. Online verfügbare Kodizes sind unter http://www.meduniwien.ac.at/medtools/medlist/cms1/ueberuns/00000095fc12aeb01/index.php verlinkt. Die Schweizer Liste ist auch ohne vorhergehender Registrierung komplett abrufbar - einfach mal "Aspirin" oder sonst etwas bekanntes auf http://www.kompendium.ch/Search.aspx?lang=de eingeben.

A4: XPath Abfragen

Nach der Deadline gibt es nun auch die "Auflösung":
  • Zu welchen Tumoren wurde noch kein Krebsmeldeblatt angelegt?

    //tumor[count(krebsmeldeblatt)=0]

  • Untersuchungen, bei denen ein Residuum entdeckt wurde

    //untersuchung[diagnose/tumorstatus="Residuum"]

  • Die Ausdehnung aller benignen Tumoren des Patienten mit der SVNR 1234010155

    //patient[@svnr="1234010155"]/untersuchung/diagnose[id(@tumor)
    [differenzierung/@name="benign"]]/ausdehnung
Das ganze auch für die Regierungs-Teilaufgabe:

  • Die Namen aller SPÖ-Sozialminister

    id(//minister[@ressort="sozial"]/@person_id)[@partei="SPÖ"]/@name
    XPath2: distinct-values( id(//minister[@ressort="sozial"]/@person_id)[@partei="SPÖ"]/@name)

  • Zurückgetretene FPÖ-Minister

    //minister[ id(@person_id)/@partei="FPÖ" and @durchgehalten="nein" ]

  • Bundeskanzler gescheiterter Regierungen

    //minister[ @bundeskanzler="ja" and ../@vorzeitige_neuwahlen="ja" ]

  • Die durchschnittliche Amtszeit von Regierungen (nur XPath 2)

    sum(//legislaturperiode/number(@end_jahr - @beginn_jahr)) div count(//legislaturperiode)
Da sind auch einige Abfragen mit id() dabei, die ResultSets werden daher in der Übungsumgebung nicht ganz wie gewohnt farblich markiert - aber sie funktionieren.

Wer vor ähnlichen Problemen steht, kann ganz einfach mit Saxon arbeiten (unterstützt auch XPath2, Download: http://saxon.sf.net). Die Abfrage muss in eine Datei geschrieben werden (zb q.txt), der Aufruf lautet dann wie folgt:

java -cp saxon9.jar net.sf.saxon.Query -s file.xml q.txt