Ich bin dann mal kurz für zwei Tage in England um mich zum Bachelor machen zu lassen :-D. Nur damit sich keiner Sorgen macht, dass hier nichts mehr kommt…
Ich bin momentan – ja immer noch – dabei meine Funktionen zu sammeln und auf REST Basis meine Schnittstellen zu definieren.
Ich hoffe, dass dann bald zum Abschluss zu bringen und dann erste Vorgänge zu implementieren.
Category: Personal
Eine Art Aha Erlebnis
Ich bin – eher durch Zufall auf folgendes Video von Stefan und Phillip gestoßen und nach dem Ansehen sind mir ein paar Dinge glasklar geworden:
Bisher hatte ich gedacht, dass REST eher als eine Art Spezialfall von HTTP ist. Seltsamerweise scheint es demnach allerdings anders herum der Fall zu sein.
Irgendwie machen jetzt auch die beiden letzten Kommentare mehr Sinn.
Ich halte die Darstellung des REST Prinzips für äußerst gelungen und hat mich seltsamerweise auch eine ganze Ecke mehr für RoR eingenommen. (Wer kann kann schon anzweifeln, wenn eine Applikation das Potential auf eine Skalierung (durch die Möglichkeit Ressourcen auf unterschiedliche URIs zu verteilen) quasi btw. eingebaut hat.
Ich werde morgen die Aktionen der verschiedenen Ressourcen auf die 4 Funktion POST/GET/DELETE/PUT abbilden.
Ich denke ich werde mich vorerst auf die Serverseite konzentrieren und als Ausgabetypen erstmal einfaches HTML und XML (welches ist ja später für YUI sowieso brauche) bemühen. Unter [1] gibt es auch schon einen Ansatz wie man die URIs dann auch ansteuern kann.
Was wir noch klar geworden ist und mich wirklich bestärkt hat ist, dass ich ein und dieselbe Anwendung als Teilstück auf eine bestehende Webseite einbinden kann (z.B. durch JS).
Allerdings bleiben ein paar Fragen, die sich während des Videos ergeben haben:
- Ich habe vor einfache HTTP Authentifizierung (Basic Authentication nach RFC 2617) zu benutzen. Stefan meinte ja in dem Video, dass man – um die Zustandslosigkeit zu erhalten – die Authentifizierung bei jedem Zugriff erfolgen soll. Ist das durch die Spezifikation von Basic Authentification gewährleistet? Wenn ich muss lese ich das in der RFC auch nach ;-). Ich habe bisher halt eher mit Sessions gearbeitet und diese als SessionIDS an die URLS angehängt (was ja REST irgendwie wiederspricht – wäre eine Ressource ja nicht mehr eindeutig durch eine URI identifizierbar)
- Bis auf Downloads habe ich mit curl noch nicht viel gemacht. Gibt es da irgendwo ein Tutorial zu? Grade so Möglichkeiten wie den Header zu ändern suche ich schon lange. Bisher habe ich – wenn ich den “Reintext” aus Abfragen erhalten wollte immer Telnet bemüht.
- Als Stefan das XML Schnippsel gesendet hat, ist auf der Auflösung des Videos nicht wirklich ersichtlich welche URI jetzt aufgerufen wird. Meiner Meinung nach müsste es ja Customer (glaube der bekam die neue Stadt) und ein PUT (weil Veränderung) gewesen sein, aber vielleicht könnte ich das noch bestätigt bekommen 🙂
- Mit den Conditional Headern: Das klingt in erster Linie ein wenig nach gestreckter/gehackter Spezifikation. Ist das eine gängige Praxis oder dient das wirklich nur zur Behandlung von ganz harten Fällen?
Abschließend noch mal ein Kompliment an Stefan und Phillip. Irgendwie haben mir die nächtlichen 45 min grade eine ganze Menge weitergeholfen. Solche Videos sollten zu Youtube ;-).
neues aus der Entwicklung ;-)
nach langer Zeit der Stille, hier mal wieder ein paar neue Infos:
Ersteinmal vielen Dank für die beiden Kommentare im letzten Beitrag…. zwei Stück sind ja fast schon Rekord.
Aber es spiegelt sehr schön auch meine erste Reaktion auf das Rest Paradigma wieder:
Es dauert eine Weile, bis man sich selber klar wird, wie man die einzelnen Ressourcen einteilt und welche einzelnen Bereiche überhaupt interessant sind für einen Benutzer.
Filtert man zum Beispiel alle Einträge auf der Clientseite und schickt immer eine komplette Liste (was meiner Meinung nach dem ganzen System widerspricht) oder legt man gleich separate “Views” für ein- und ausgehende Einträge an (was ich jetzt tatsächlich auch so machen werde).
Auf Anraten von Phillip bin ich grade dabei die Grundprozesse zu sammeln und zu strukturieren. Also anders als die Grundfunktionen möchte ich hier dann auch die Vorgänge im System sammeln.
Also wenn zum Beispiel ein neuer Benutzer angelegt wird, wird erst ein Formular geladen, indem der Nutzer seine Daten einträgt, dann werden die Daten auf Stimmigkeit und Vollständigkeit überprüft und ggf. eine Fehlermeldung zurück gesendet. Es folgt eine Bestätigungsemail an den Ersteller, welche dieser nutzt, um seinen Account letztendlich zu aktivieren. Schon hier sind Fragen offen: zum Beispiel, soll es die Möglichkeit geben, dass nur ein Admin/Projektleiter neue Benutzer anlegen kann. Erhält ein Verantwortlicher eine Email über die Erstellung eines neuen Nutzers, sodass dieser in eine bestehende Gruppe (oder ein bestehendes Projekt) eingeordnet werden kann?
Ich denke das ich ein wenig Zeit investieren muss, aber dass sich diese Zeit definitiv auszahlt am Ende.
Ich werde meine Arbeit übrigens unter dem Titel
Aufgaben kollaborativ und webbasiert verwalten- Realisierung einer Web-Anwendung mit Enterprise Java Beans und Yahoo Web Framework
morgen anmelden. Vielen Danke für den Input Phillip :-). Gefällt mir so wirklich besser. Ab dann läuft die Zeit :-o.
RESTliches
Ich habe lange Zeit nicht mehr gemeldet.
Das lag zum einen daran, dass es viel drumherum zu tun gab und zum zweiten daran, dass ich momentan viele vage Dinge habe, die ich erstmal in eine wirkliche Form bringen will. So ungefähr wie eine Zettelsammlung, die man dann endlich Llochen und einheften möchte.
Ich fange erstmal damit an, dass ich meine – bisherigen – Funktionen zu meinen Objekten sortiere. Bisher habe ich an Objekten nur User und Entries. Wohlgemerkt, es geht hier nicht um Methoden sondern einzig und alleine um Funktionen. D.h. die Funktion wäre das was in der URI dann stehen würde.
z.B. /Users/1/inbox. Dann wäre Users also mein Objekt (dies wird auf Java Ebene dann von der Klasse UserService abgebildet) und inbox wäre die Funktion. Natürlich wird es in der Klasse UserService eine Methode Namens inbox geben, allerdings auch zusätzliche Methoden, welche nicht dem REST Paradigma unterworfen sind.
Hier also meine kleine Übersicht:
- Entries
- create
- update
- delete
- send
- list
- mark
- Dependencies
- Users
- create
- update
- delete
- login
- logout
- list
- Inbox
- Outbox
Eine Erklärung erfolgt in einem späteren Post. Sobald ich die einzelnen Funktionen eingegrenzt habe. Zudem haben sich folgende Änderungen ergeben:
- Ein Eintrag kann mehrere Empfänger haben. Damit kommen folgende Problem auf mich zu:
- Ist ein Eintrag erledigt, wenn ein Empfänger ihn als erledigt markiert? Oder alle? Vielleicht wahlweise?
- Wenn es möglich ist, Einträge “weiter zu vermitteln”, wie stellt man sicher, dass die anderen Empfänger erhalten bleiben? Kann der aktuelle Empfänger weitere hinzufügen?
- Wie bildet man das in der Datenbank ab (zum Glückt gibt es dafür ja schon eine geeignete Lösung)
Dazu gesellen sich dann noch Probleme, dass man zum Beispiel ja eindeutig einen aktuell Verantwortlichen für einen Eintrag ermitteln sollen kann. Bei wechselnden Empfängern und vor allem mehreren Empfänger könnte das schwierig werden. Vor allem müsste man dann auch über eine erweitere Rollenverteilung nachdenken. Stichwort Verantwortlich und Bearbeiter.
- eistens ist es notwendig, dass eine Aufgabe in Unteraufgaben “aufgebrochen” wird. So soll es möglich sein, dass ein Eintrag beliebig(?) viele Untereinträge auf beliebig(?) tief verschachtelten Ebenen hat. Dazu wird man den “Erledigt Status” von “unten nach oben durchreichen” müssten. Wenn aus Entry 12 Entry 12.1 und Entry 12.2 erledigt sind, sollte auch Entry 12 als erledigt markiert sein.
Zu guter Letzt noch ein paar Links, die sich so fanden:
Ajax mit HTTP Basic Auth (YUI) [1] womit schon mal ein Problem gelöst ist, was in meinem Hinterkopf festsaß.
REST with JSP [2] irgendwie sehe ich nur noch innoQ – so langsam wird man paranoid :-).
REST Web Services [3] ist ein schönes Beispiel zu REST und da wird auch der Unterschied zu SOAP deutlich.
cotodo lebt :-)
Collaboration ToDo List. Klingt irgendwie schön nach web 2.0.
Also das einchecken in Subversion hat auch recht schmerzlos funktioniert. Noch mal vielen Dank Stefan für die Tipp.
Noch mal in aller Klarheit:
https://www.innoq.com/svn/Sandbox/<user>
Momentan sitze ich mal wieder über meiner UML Skizze und versuche eine Art Service Struktur für meine Persitenten Objekte zu erstellen. So langsam finde ich gefallen daran, vor allem merkt man nach einer Weile, dass die Vorschläge aus dem Buch “Pro EJB 3. Java Persistence API” – (aPress) von Mike Keith und Merrick Schincariol ziemlich sinnvoll sind.
(Amazon Link)
Letztendlich geht es jetzt darum, die Funktionalität, die ich haben möchte soweit zu kapseln, dass sie sich mit dem vorgeschlagenen Design abbilden lässt.
Ich denke ich werde eh noch genug eigene Wege einschlagen – irgendwie liegt mir das im Blut :-).
Ich habe sogar ein Beispiel gefunden, wie man relative einfach DB Update von einer Programmversion auf die nächste mit JPA berwerkstelligen kann (Das war ein Punkt in unserer letzten Diplomandenrunde).
WSC: our Team in Australia
Here are some Links about our Solar car racing team that is currently taking part at the 20th world solar challenge from Darwin to Adlaide!
More infos about SolarWorld No1. The official Blog and the webblog of Ralf Zweering with some additional pictures.
And there is even a headline at heise.de!
I wish our team all the best. It is an incredible piece of technology. We are now at the 5th place!
Subversion – how to do?
Ich wollte grad versuchen mein bisherigen Projekt auf den innoQ subversion server zu schieben. Allerdings hat es bisher noch nicht so funktioniert.
Weder
http://www.innoq.com/secure noch
https://www.innoq.com (nach dem wiki sollte das ja nach innoq.de weitergeleitet werden)
noch https://www.innoq.de/secure gingen.
Bei letzterem kam allerdings ein authentification error.
Vielleicht kann mir ja jemand einen Tipp geben.
erster Eintrag erstellt!
Mittlerweile konnte ich jetzt auch schon den ersten Eintrag erstellen. Das ganze schaut noch recht umständlich aus, weil noch so gar keine Frontends existieren:
public String addEntry(){ User recipient = (User)em.find(User.class, 3); Entry important = new Entry(); Calendar cal = Calendar.getInstance(); cal.set(2007, 12, 15); Date end = (Date) cal.getTime(); important.setSender(user); important.setRecipient(recipient); important.setPriority(1); important.setStatus(10); important.setTitle("start with ADAM&EVA"); important.setDeadLine(end); important.setSendDate(new Date()); important.setContent("no text"); em.getTransaction().begin(); em.persist(important); em.getTransaction().commit(); em.close(); return important.toString(); }
Es gibt – natürlich – den Benutzer mit ID 3 (als Empfänger) schon und auch user ist als Attribut der Klasse schon gesetzt.
Letztendlich wird der Eintrag auch abgespeichert – wenn man so will die erste wirklich sinnvolle Funktion :-).
Mittlerweile habe ich mich dazu entschlossen gemäß MVC alle POJOs für JPA im Package de.hausswolff.diplom.M zu speichern und im Package de.hausswolff.diplom.C die Controller (in dem Buch hießen diese Serviceklassen, also für Klasse User aus dem M Package wäre es dann halt UserService. Die Ausgabe in Form von normalen Servletts werde ich dann komplett in einem V Package bündeln.
Was mich noch ein wenig beschäftigt ist, dass ich ja gerne nach dem REST Prinzip vorgehen möchte und also unter /user/3/inbox/5 den Eintrag von Benutzer mit der ID 3, den er erhalten hat (inbox) mit der ID 5 erhalten möchte. Ich nehme mal sehr stark an, dass es dafür eine Java Lib gibt. Habe aber auch noch nicht großartig gesucht. Ich werde – sobald ich die 3-Tabellen Lösung zum Laufen bekomme (siehe letzter Eintrag – war leider ein wenig spät/früh gestern/heute ^^) – mal anfangen die neue Package Struktur als UML zu erstellen.
JPA YEEHA!
Besser später als nie, hier also dann mal – nach laaaanger Zeit mal wieder – mein aktueller Status.
Mittlerweile bin ich ein ganzes Stück weiter und so fange ich sogar an, dem ganzen System von Persistence etwas abgewinnen zu können. Einzig die Frage bleibt, wieso JPA per default partout alle Feldnamen als groß schreibt. Naja das wird sich sicherlich auch noch klären. Aber zuersteinmal der Reihe nach:
Das – anfängliche Problem, dass ich ja einen Integer Primary Key brauche, aber auch zum Beispiel auch ein User Objekt anhand eines Namens (der ja nach meiner Definition auch eindeutig sein soll) erstellen will, ergab sich die Zwickmühle, dass es ein System geben muss, welche einem quasi einfache SQL Searches erlaubt… gibt es auch.
Anhand einer Präsentation, von Phillip fand sich dann auch eine recht kurze (und demnach schmerzlose) Lösung:
@Entity @Table(name = "Users") @NamedQuery(name = "findWithName", query = "SELECT u FROM User u WHERE u.name = :Name") public class User { ... }
Das sagt der Klasse, dass sie, wenn ich eine Query namens (“findWithName”) ausführe, das nachfolgende SQL Statement benutzen soll und demnach auch den Parameter ‘Name’
Der Aufruf schaut dann so aus:
User user = (User) em.createNamedQuery("findWithName") .setParameter("Name", "TestUser").getSingleResult();
Nunja ein schöner, langer Aufruf. Aber immerhin wird mir ein User Objekt erstellt, wenn ein User mit Namen ‘TestUser’ existiert!
Kommen wir zum nächsten Punkt – mein Lieblingspunkt an diesem Morgen, weil das mich ziemlich viel Zeit und Schweizß gekostet hat (obwohls doch eigentlich so einfach ist) – die Kardinalitäten – ODER AUCH -” wie papern, wer n Eintrag an’nen User?”
Ich bin in mich gegangen und kam mit der Entscheidung aus mir (sagt man das so?), dass ich für jeden Eintrag, der von User A nach User B geschickt wird, ein Eintrag in der Datenbank erstellt wird. Also selbst, wenn User A an B und C die gleiche Aufgabe verteilen würde, würden zwei Einträge erstellt. Ich weiß, dass es dann recht unmöglich ist, zum Beispiel zwei User für eine Aufgabe vorzusehen und diese Aufgabe dann bei User B erledigt ist und bei User C noch offen – letztendlich ging es mir auch ersteinmal darum, die Abhängigkeiten hin zu bekommen.
Also erstmal die Veriante mit Stützrädern (zwei Tabellen) und dann hinterher (so morgen) schau ich mal, ob ich das auch freihändig schaffe (so drei Tabellen).
Letztendlich schaut das mit JPA ähnlich aus wie bei Willem und seinen RoR (gabs da nich mal n Lied mit RoR, RoR, RoR the Boat? aber ich glaube das war Row… egal).
Also vielleicht zuerst einmal die beiden Klassen und wie diese zusammenhängen:
Ja die Attribute laden quasi dazu ein, auf eine 3. Tabelle auszulagern ;-).
Es gibt also zwischen User und Entry exact zwei 1-zu-N Beziehungen:
1. Hat ein User genau eine Inbox mit N erhaltenen Entries
2. Hat ein User genau eine Outbox mit N versandten Entries
Da Willem nich Ruhe geben wollte, habe ich die Tabellen gleich mal Pluralisiert (okay ist auch sonst ne ganz gute Idee) und die IDs _id getauft.
Für JPA geht man nun wie folgt vor:
... public class User { ... @OneToMany(mappedBy = "recipient") private Collection inbox; @OneToMany(mappedBy = "sender") private Collection outbox; ... } ...
sagt einem, dass jeweils die Attribute (eigentlich die Items aus den Collections) inbox und outbox an das Attribut (und hierbei geht es wohl wirklich um das Objekt ansich) “recipient”/ “sender” gemapped werden.
In der Klasse Entry muss dann natürlich quasi “das Kind konfiguriert werden” (das klingt jetzt seltsam aber im Moment fällt mir nix gescheiteres ein):
... public class Entry { ... @ManyToOne() @JoinColumn(name="recipient_id") private User recipient; @ManyToOne() @JoinColumn(name="sender_id") private User sender; ... } ...
Na gemerkt? ManyToOne anstatt OneToMany….ach war klar? Na,… okay :-).
Nun werden halt nur noch schnell die Feldnamen aus der DB Table angegeben und besagte Objekte erstellt ( recipient/ sender ). Geht ja eigentlich ganz schnell…
Das Setten/Getten probiere ich dann mal morgen und dann auch gerne mit 1+1+1 = 3 Tabellen. Gibt einem ja dann doch ein wenig mehr Möglichkeiten.
Das EJB3 Buch ist übrigens gut. Man liest, schreibt, sucht dann noch nen anderes Beispiel und dann versteht man es erst ;-). Nach und nachen rücken aber erster und letzter Schritt immer näher zusammen.
Ich wünsche allen eine erfolgreiche Woche.
after 1.508,4 km: we are back in the rhine-ruhr area!
After five thrilling days on the road, with amazing sunny weather, we made our way back home.
We met some new peoples. Always nice to know new faces and get new impressions.
The Tip of the Trip is Hohenheim where we slept one night a took part on one day of the welcome week for the new students at the university of Hohenheim.
Just for the record:
More picture in my Picture Gallery. If you want to browse them, just drop me a line or send me an email!
So thank you very much to all the nice friends, that gave us a place to sleep for one (or two) nights. You are welcome in here in my place if you need a place to rest for one night :-).