SlideShare une entreprise Scribd logo
1  sur  6
Télécharger pour lire hors ligne
Web Lift-Webframework




    Twitter nachgebaut
    mit Lift
    Wer sich mit Scala beschäftigt, kommt an Lift nicht vorbei: Wie kaum ein anderes Produkt
    hat dieses innovative Webframework dazu beigetragen, das Scala-Ökosystem aufzubauen.
    In diesem Artikel zeigen wir anhand eines konkreten Fallbeispiels die Gründe für diesen
    Erfolg.




    von Heiko Seeberger und Johannes Hohenbichler

             as könnte als Vorlage besser     anderen Benutzern folgen und natürlich    noch unter dem Namen Scala with Sails.
             geeignet sein als Twitter [1]?   das Nachrichtenverschicken und -an-       Sein Ziel war und ist es noch heute, ein
             Einerseits dürfte es kaum je-    zeigen unter Verwendung der Web-2.0-      einfach zu benutzendes, sicheres und
    manden in unserer Branche geben, der      Features Ajax und Comet. Doch bevor       höchst produktives Webframework zu
    diese Art des Zwitscherns nicht kennt.    wir uns die Hände schmutzig machen,       schaffen. Dazu bedient sich Lift der bes-
    Andererseits steht Twitter trotz über-    ein kurzer Überblick über Lift.           ten Konzepte anderer Frameworks und
    schaubarem Funktionsumfang gera-                                                    ergänzt sie um eigene innovative Ideen.
    dezu idealtypisch für heutige moderne     Von den Ursprüngen bis heute              Beispiele für dieses Rosinenpicken sind
    Webapplikationen. Wir werden mit          Im Jahr 2006 startete David Pollak [2],   an Wicket [3] angelehnte Templates,
    Chatter – unserem Nachbau – die wich-     inspiriert von vielfältigen Erfahrungen   CRUD-Unterstützung wie bei Rails
    tigsten Features auf vereinfachte Weise   mit Programmiersprachen und Frame-        [4] oder Djangos [5] „More than just
    umsetzen: Registrieren und Anmelden,      works, die Arbeit an Lift, ursprünglich   CRUD“ bei der Benutzerverwaltung.




 52 javamagazin 5|2010                                                                                         www.JAXenter.de
Lift-Webframework Web



Heute sehen wir eine große und sehr le-        Abb. 1: Initia-
bendige Lift-Community mit mehr als             le Startseite

zehn aktiven Committern und etliche
produktive Anwendungen auf Basis von
Lift, z. B. Foursquare.com [6] oder ESME
[7]. Derzeit befindet sich bereits die Ver-
sion 2.0 in der Entwicklung, die vermut-
lich auf Scala 2.8 aufsetzen wird.             unter weiglewilczek.com/labs/chatter             Eine Anmerkung: Selbstverständ-
                                               einen Blick auf die laufende Anwendung       lich unterstützt Lift internationalisierte
Ein modularer Baukasten                        in Endausbaustufe werfen. Einfach mit        Anwendungen, aber um die Dinge noch
Lift bringt als „Full Stack Framework“         E-Mail-Adresse registrieren und dann         einfacher zu halten, blenden wir das hier
alles mit, um eine komplette Webappli-         loslegen. Zum Testen am besten mit zwei      aus und halten uns konsequent an Eng-
kation zu entwickeln. Dazu gehören             unterschiedlichen Browsern, um die Ak-       lisch.
typischerweise Templates, Menüs und            tualisierung der Nachrichten via Comet
Zugriffskontrolle, Persistenz, CRUD-           sehen zu können.                             Lift konfigurieren
Support und eine komplette Benutzer-               Den kompletten Sourcecode gibt           Natürlich müss en w ir uns erer
verwaltung. Aber auch ausgefallenere           es unter der Eclipse Public License bei      Webapplikation beibringen, dass sie
Features wie PayPal-Anbindung, Open-           github.com/weiglewilczek/chatter zum         „geliftet“ ist, und das tun wir über ei-
ID- oder OAuth-Schnittstellen sowie            Browsen oder Herunterladen. Die ein-         nen Servlet-Filter in web.xml. Scala ist
Support für JSON-APIs werden ange-             zelnen Schritte, in denen wir Chatter        so flexibel und ausdrucksstark, dass
boten. Doch es gibt keinen Grund, vor          entwickeln werden, sind mit Tags (z. B.      Lift selbst auf Konfigurationsdateien
dieser Fülle an Features zu erschrecken.       0.1-template) versehen, sodass Sie die       in XML verzichten kann. Stattdessen
Lift ist modular aufgebaut und wir kön-        Entwicklung im Sourcecode nachvoll-          wird Lift in der Scala-Klasse Boot kon-
nen wählen, was wir verwenden möch-            ziehen können. Selbstverständlich sind       figuriert, die per Default im Verzeichnis
ten und was nicht. So können wir z. B. die     Tickets für Fehler oder Erweiterungs-        liftweb.bootstrap erwartet wird, bei uns
mit lift-mapper mitgelieferte Benutzer-        wünsche sehr gern gesehen.                   aber via Servlet-Filter-Parameter nach
verwaltung verwenden oder auch eine                                                         com.weiglewilczek.chatter verschoben
eigene bzw. vorhandene.                        Das Projekt aufsetzen                        ist. Neben einigen nützlichen Vorgaben
                                               Lift nutzt selbst Maven [9] und bietet       für Formatierung und Internationa-
Ein funktionales Framework                     uns mit verschiedenen Maven Arti-            lisierung enthält Boot eine besonders
Wozu eigentlich ein weiteres Webframe-         facts eine sehr angenehme Möglichkeit,       wichtige Zeile: LiftRules addToPackages
work? Löst Lift unsere täglichen Aufga-        unser Projekt aufzusetzen. Selbstver-        getClass.getPackage. Hiermit bestim-
ben anders und vor allem auch besser           ständlich können wir Lift-Projekte auch      men wir, dass Lift im Package com.
als andere? Dank Scala: Ja. Eine kürzlich      in der IDE unserer Wahl oder mit Ant         weiglewilczek.chatter nach Sub-Pa-
durchgeführte Umfrage auf JAXenter             entwickeln, aber für Chatter bleiben         ckages für Snippets und Comet-Klassen
[8] hat ergeben, dass für die Leser Scala      wir Maven treu, weil das einiges verein-     – dazu später mehr – suchen soll.
die JVM-Sprache mit dem größten Po-            facht, insbesondere das Management
tenzial ist. Und dieses Potenzial hebt Lift,   der Abhängigkeiten. Wir verwenden            Templates für das UI
indem es insbesondere die funktiona-           Lift 2.0-SNAPSHOT , d. h. den aktuel-        Wie erstellen wir eigentlich Webseiten
len Features, Traits sowie das mächtige        len Entwicklungsstand für die Version        mit Lift? Am einfachsten mit Templates:
Typsystem von Scala nutzt. Ein gutes           2.0 sowie Maven 2.2.1. Mit dem Arti-         Das sind XHTML-Seiten, die keiner-
Beispiel hierfür: Wenn ein Formular-           fact lift-archetype-basic erhalten wir ein   lei Logik enthalten. Doch wie kommen
feld übertragen oder ein Button geklickt       einfaches Projekttemplate. Da wir hier       dann die dynamischen Elemente auf die
wird, dann soll etwas passieren, und das       grundlegende CSS- und Scala-Kennt-           Seite? Das funktioniert ähnlich wie bei
geben wir in Lift einfach in Form von          nisse voraussetzen, reichern wir unser       Wicket, nur dass wir bei Lift nicht über
Funktionen an. Dies entspricht viel bes-       Projekt ohne weitere Erläuterungen um        IDs, sondern über spezielle Elemente
ser unserem intuitiven Verständnis, als        ein Stylesheet sowie Hilfsklassen für        mit eigenen Namespaces gehen, die so-
z. B. die Kapselung in Form- und Con-          die Locale-abhängige Datumsforma-            zusagen als Platzhalter für den dynami-
troller-Klassen, wie wir sie bei typischen     tierung an. Nach ein wenig Tuning von        schen Inhalt stehen.
OO-Frameworks finden.                          POM und Projektstruktur erhalten wir
                                               unser Projekttemplate.
Chatter in Action                                  Um Chatter lokal laufen zu lassen,         Listing 1 : index.xhtml
Bevor wir loslegen, sollten wir uns eine       genügt es, mvn jetty:run im Projektver-        <lift:surround with="default" at="content">
Vorstellung davon machen, was wir im           zeichnis abzusetzen. Dann können wir            <div>Welcome to Chatter</div>
Folgenden Schritt für Schritt entwi-           unter http://localhost:8080 auf die Start-     </lift:surround>
ckeln. Das geht am besten, indem wir           seite zugreifen (Abb. 1).




www.JAXenter.de                                                                                                     javamagazin 5|2010 53
Web Lift-Webframework


                          Besonders praktisch: Templates kön-       lift:ChatterInput. Damit referenzieren                   bzw. anzumelden. Lift bringt mit dem
                      nen verschachtelt werden. Im Verzeich-        wir das Snippet ChatterInput, eine Sca-                  Persistenzmodul lift-mapper für relati-
                      nis templates-hidden liegt unser „Wur-        la-Klasse, die für das Dynamisieren des                  onale Datenbanken eine komplette Be-
                      zeltemplate“ default.xhtml. Es enthält        Inhalts zuständig ist. Im Inhalt selbst fin-             nutzerverwaltung mit anpassbarem UI
                      das HTML-Skelett für all unsere Seiten.       den wir die statischen HTML-Elemente                     und Persistenz mit. Wir verwenden den
                      Über ein spezielles Element aus dem lift      und zwei spezielle Platzhalterelemente                   Trait MegaProtoUser (zugegeben, das ist
                      Namespace definieren wir einen Anker-         im chatter Namespace. Wir haben die                      ein komischer Name), der Attribute wie
                      punkt, um den eigentlichen Inhalt ein-        freie Wahl bei der Benennung des Name-                   E-Mail, Passwort, Vor- und Nachname
                      zubinden: <lift:bind name="content"/>.        spaces und müssen nur darauf achten,                     etc. besitzt und missbrauchen den Vor-
                          Doch was wird dort eingebunden?           dass das betroffene Snippet ihn auflöst.                 namen als einzigen Namen, indem wir
                      Das ist der Inhalt aus dem Template, das      Genau das tut ChatterInput in der ren-                   den Anzeigenamen ändern (Listing 4).
                      wir aufrufen, also z. B. von der Seite in-    der-Methode (Listing 3). Durch die                            Im dazugehörigen Companion
                      dex.xhtml. Diese ist, wie in Listing 1 dar-   bind-Methode werden die Elemente                         Object, zu dem wir den Trait MetaMe-
                      gestellt, nur ein Fragment einer XHTML        chatter:text und chatter:submit durch                    gaProtoUser mixen, konfigurieren wir
                      -Seite. Mittels lift:surround geben wir       die HTML-Elemente für eine Textarea                      unter anderem, welche Attribute wir
                      das Template und den Ankerpunkt an,           und einen Submit-Button ersetzt. Der                     verwenden, dass wir auf E-Mail-Validie-
                      sodass die Willkommensnachricht in            Methode textarea übergeben wir einen                     rung verzichten und dass die Seiten für
                      das Default-Template eingebettet wird.        leeren String als Default-Wert und eine                  Registrierung, Log-in etc. von unserem
                                                                    Funktion, die ausgeführt wird, sobald                    Default-Template umgeben sein sollen
                      Interaktionen mit Snippets                    das Formular zum Server geschickt                        (Listing 5).
                      Nun wollen wir als Erstes eine Eingabe-       wird. In unserem Fall loggen wir einfach                      Wie aktivieren wir nun unsere Be-
                      möglichkeit für Nachrichten schaffen,         die Eingabedaten. Die Methode submit                     nutzerverwaltung? Indem wir in Boot
                      d. h. wir benötigen ein Formular. Wie         erwartet eine Bezeichnung für den Sub-                   zum einen eine Datenbankverbindung
                      bereits erwähnt, setzt Lift zur Bearbei-      mit-Button sowie ebenfalls eine Funkti-                  konfigurieren und zum anderen unse-
                      tung von Formularen auf Funktionen. In        on. Hier tun wir allerdings nichts.                      re User-Klasse mittels Schemifier.sche-
                      unserem Fall wollen wir erst einmal nur                                                                mify in das Datenbankschema bringen
                      die Eingabe loggen. Dazu nehmen wir           Ready-to-use-                                            (Listing 6). Das funktioniert so ähnlich
                      ein Formular in unser Template für die        Benutzerverwaltung                                       wie in Hibernate die Einstellung ddl.
                      Startseite auf (Listing 2). Wir umgeben       Als Nächstes wollen wir uns darum küm-                   auto. Wir verwenden hier H2 [10] im In-
                      den Inhalt mit dem speziellen Element         mern, uns als Benutzer zu registrieren                   Process-Modus als Datenbank, aber lift-

Listing 2 : index.xhtml                                                          Listing 5 : User.scala
<lift:surround with="default" at="content">                                      object User extends User with MetaMegaProtoUser[User] {
 <lift:ChatterInput form="post">                                                  override def signupFields = firstName :: email :: password :: Nil
  <div>What's happening?</div>                                                    override def skipEmailValidation = true
  <div><chatter:text/></div>                                                      ...
  <div class="right"><chatter:submit/></div>
  <hr/>                                                                          Listing 6 : Boot.scala
 </lift:ChatterInput>
</lift:surround>                                                                 ...
                                                                                 val dbVendor =
                                                                                  new StandardDBVendor(Props get "db.driver" openOr "org.h2.Driver",
Listing 3 : ChatterInput.scala
                                                                                          Props get "db.url" openOr "jdbc:h2:chatter",
class ChatterInput extends Logging {                                                      Props get "db.user",
 def render(xhtml: NodeSeq) = {                                                           Props get "db.password") {
  def handleUpdate(text: String) {                                                override def maxPoolSize = Props getInt "db.pool.size" openOr 3
   logger debug "Sending message: %s".format(text)                               }
  }                                                                              DB.defineConnectionManager(DefaultConnectionIdentifier, dbVendor)
  bind("chatter", xhtml,                                                         Schemifier.schemify(true, Log infoF _, User)
    "text" -> textarea("", handleUpdate _),                                      ...
    "submit" -> submit("Update", () => ()))
 }                                                                               Listing 7 : Boot.scala
}
                                                                                 ...
                                                                                 val ifLoggedIn = If(() => User.loggedIn_?,
Listing 4 : User.scala                                                                   () => RedirectResponse(User.loginPageURL))
class User extends MegaProtoUser[User] {                                         val homeMenu = Menu(Loc("home", List("index"),"Home", ifLoggedIn))
 override def firstNameDisplayName = "Name"                                      val menus = homeMenu :: User.menus
override def getSingleton = User                                                 LiftRules setSiteMap SiteMap(menus: _*)
                                                                                 ...




                   54 javamagazin 5|2010                                                                                                               www.JAXenter.de
Anzeige




Agile Projekte – stabil oder fragil?
Um agile Projekte zu skalieren, brauchen Teams die passenden Werkzeuge
Agile Prozesse mit agilen Praktiken haben sich in vielen Projekten      des Repositories herstellen. Beim Chatten erkennt das System
bewährt. Zu den Erfolgskriterien agiler Projekte zählt die gelunge-     automatisch Schlüsselwörter wie „Task“ oder „Story“ und erzeugt
ne Zusammenarbeit. Daher sind die Teams von überschaubarer              zusammen mit einer Nummer den Link zum entsprechenden
Größe. Idealerweise arbeiten sie zusammen in einem Zimmer, an           Work-Item. Der Chat-Partner kann diesen Link anklicken und hat
einer gemeinsamen Werkbank. Aber lässt sich dieses dynamische           dann ebenfalls das Work-Item auf dem Schirm. Der Chat kann im
Setting auch auf andere, größere Projekte übertragen, damit der         Kontext weiter gehen.
Erfolg der agilen Projekte auch auf diese abstrahlt?
Das Problem: Je höher man Projekte skaliert, desto weiter entfernt      Eigenschaften in die IDE integrieren
man sich von den bekannten Erfolgsvoraussetzungen: Das Team             Dies alles ist nur dann bequem möglich, wenn all diese Eigen-
ist nicht mehr überschaubar und häu g über mehrere Standorte            schaften in die IDE der Entwickler eingebettet sind. Das leistet IBM
verteilt. Außerdem gehören die Mitglieder oft verschiedenen Orga-       Rational Team Concert durch die Integration des Clients sowohl in
nisationen an, arbeiten beispielsweise bei einer Partner rma oder       Eclipse als auch in Visual Studio .NET.
einem Zulieferer.
                                                                        Continuous Integration ist eine weitere wichtige Praxis in agilen
Diese Veränderung der Rahmenbedingungen führt zu Problemen in           Projekten. Sie hat bei großen, verteilten Projekten eine besondere
der Kommunikation und behindert die Abstimmung innerhalb des            Bedeutung, denn hier können Integrationsprobleme besonders
Teams. Der Informations uss ist gestört, und damit verliert man         unangenehm und aufwändig werden. Daher ist ein Source-Code-
einen der wichtigsten Vorteile der agilen Prozesse. Bewährte Tech-      Management-System unabdingbar, das auch standortübergreifend
niken wie das Arbeiten mit Taskboards funktionieren nicht mehr.         einsetzbar ist. Durch ein solches System können alle Entwickler auf
                                                                        den Quellcode zugreifen und diesen leicht integrieren.
Moderne Werkzeuge entschärfen Probleme
Diese Probleme lassen sich mit modernen Werkzeugen zur agilen           Bei Fehlern alten Zustand wiederherstellen
Planung entschärfen. Ganz wichtig dabei ist ein gemeinsames             In Rational Team Concert ndet man eine enge Verzahnung mit
Repository, in dem sich alle Artefakte des Projektes be nden            dem Build-Management-System. Kontinuierlich und einfach lassen
und den Teammitgliedern zur Verfügung stehen. Damit sind die            sich lokale und globale Builds erstellen. Bei Fehlern können die
Backlogs mit ihren Stories, Epics und Tasks für alle immer sichtbar.    Mitarbeiter über einen Snapshot des Repositories den alten Zu-
Produktverantwortliche und Teammitglieder werden bei der Ver-           stand ohne viel Aufwand wiederherstellen.
waltung des Backlogs deutlich entlastet. Auch das Taskboard lässt
                                                                        Dieses gemeinsame Repository macht auch eine leistungsfähige
sich elektronisch p egen, was den Projektfortschritt wieder für alle
                                                                        Verknüpfung zwischen Quellcode und Stories bzw. Work-Items
sichtbar macht. Gra ken über den Zustand des Projektes wie zum
                                                                        möglich. Per Knopfdruck ndet man heraus, warum welche Pro-
Beispiel Burndown-Charts lassen sich automatisiert erstellen und
                                                                        grammzeile von wem verändert wurde. Der umgekehrte Fall ist fast
spiegeln immer einen aktuellen Projektstand wider.
                                                                        noch wichtiger: Welche Änderungen waren nötig, um eine Story zu
Damit lassen sich agile Vorgehensmodelle, wie zum Beispiel              realisieren oder um einen Fehler zu beheben? Nur so lassen sich
Scrum, bereits sehr ef zient einsetzen. Dennoch bleibt es bei der       behobene Fehler auch in mehreren Versionen sicher nachkorrigie-
Fülle von Informationen für die Teammitglieder schwierig, die für sie   ren.
wichtigen und relevanten Informationen zu verfolgen und zu erfas-
                                                                        Agile Vorgehensweisen lassen sich nur skalieren, wenn den Teammit-
sen. Arbeiten zum Beispiel mehrere Personen an unterschiedlichen
                                                                        gliedern dafür die geeigneten Werkzeuge zur Verfügung stehen. IBM
Standorten an einer Story, so fällt es allen Beteiligten schwer, sich
                                                                        hat diese Erfahrung bei der Entwicklung von Rational Team Concert
ständig zu synchronisieren. Kontinuierlich treffen im Repository
                                                                        selbst gemacht und genutzt. Denn das IBM-Entwicklerteam hat bei
verfeinerte Anforderungen seitens der Business-Owner ein. Um
                                                                        der Arbeit bereits Alphaversionen des Produkts verwendet und die
diese Änderungen alle zur Kenntnis zu nehmen, müssten die Team-
                                                                        frischen Erfahrungen nahtlos in der Weiterentwicklung und Vollen-
mitglieder fortlaufend das Repository durchforsten.
                                                                        dung der Software umgesetzt. Dabei ist mit Rational Team Concert
Viel praktischer und leichter ist es hingegen, wenn die Teammitglie-    eine vollständig interaktive Entwicklungsumgebung für größere,
der Änderungen im Repository per RSS-Feed erhalten. In diesem           unternehmensweite Teams entstanden. Ein Werkzeug, mit dem sich
Fall bekommen sie sofort eine Nachricht im eigenen Event-Log,           Agilität skalieren lässt.
wenn sich in der Story etwas ändert. Sie sind also immer auf dem
aktuellen Stand der Informationen. Dieser Event-Log ist individu-       Interesse?
ell auf den Mitarbeiter zugeschnitten: Er kann selbst auswählen,
über welche Veränderungen er informiert werden will. Auf diese          Dann setzen Sie sich noch heute mit uns in Verbindung.
Weise ießen die Informationen, die in agilen Projekten in den Daily     Ansprechpartner: Werner Schoepe
Stand-Ups weitergegeben werden, auch standortübergreifend.              Telefon: +49-211-476-2163
                                                                        E-Mail: werner.schoepe@de.ibm.com
Anforderungen „just in time“ festhalten                                 Weitere Infos und Downloads nden sich unter:
                                                                        www.ibm.com/software/products/de/de/rtc-standard
Die Stories und Tasks spielen im Repository eine zentrale Rolle
beim Informationsaustausch. Hier können die Anforderungen               oder direkt auf der Community Site:
„just in time“ festgehalten werden. Zusätzlich bieten sie Rubri-        www.jazz.net
ken für Diskussionen. So kann man im virtuellen Team Probleme
und Fragestellungen gleich im Kontext der Stories erörtern. Die         Treffen Sie Werner Schoepe auf der JAX 2010 – zu seinem Vortrag
entsprechenden Änderungen sehen die Beteiligten sofort in ihrem         „Die neue Herausforderung: Skalierung von agilen Projekten!“
Event-Log.                                                              am Montag, 3. Mai, 11:45 – 12:30 Uhr
Instant Messaging ist heute an vielen Arbeitsplätzen Standard.          Oder auf dem IBM-Stand.
Integriert in die IDE lässt sich auch hier ein Kontext zu Objekten
Web Lift-Webframework


                      mapper unterstützt natürlich alle gängi-             kümmert sich um Menüs und optio-                         cken bzw. empfangene Nachrichten
                      gen relationalen Datenbanken.                        nale Zugriffskontrolle. Hier definieren                  anzeigen. Dazu ergänzen wir als Erstes
                                                                           wir das Home-Menü, sodass wir nur als                    unser Formular um einen Bereich zur
                      Menüs und Zugriffskontrolle                          angemeldete Benutzer Zugriff haben,                      Anzeige der Nachrichten (Listing 8).
                      Jetzt müssen wir dafür sorgen, dass nur              sowie das Menü für die Benutzerverwal-                   Ähnlich wie ein Snippet, referenzieren
                      angemeldete Benutzer Chatter verwen-                 tung, das wir von unserer User-Klasse                    wir mit dem Element lift:comet und des-
                      den können. Dazu müssen wir erst noch                quasi geschenkt bekommen.                                sen type-Attribut eine Klasse, die sich
                      das Menü und die Seiten der Benutzer-                                                                         um Comet kümmert. Weiter finden wir
                      verwaltung anzeigen. Das konfigurieren               Chat mit Ajax und Comet                                  im Template einen Block mit statischen
                      wir wiederum in Boot, indem wir eine                 So weit, so gut, aber das Wichtigste fehlt               HTML-Elementen und Platzhaltern zur
                      Sitemap definieren (Listing 7). Diese                noch: Wir wollen Nachrichten verschi-                    Anzeige einer Nachricht.




Listing 8                                                                               Listing 11 : ChatterInput.scala
...                                                                                     ...
<lift:comet type="ChatterMessages">                                                     def handleUpdate(text: String) {
 <messages:list>                                                                         val message = ChatterMessage(user.id.is, user.shortName, now, text.trim)
  <div>                                                                                  logger debug "Sending Chatter message to server: %s".format(message)
   <span class="messageName"><message:name/></span>                                      ChatterServer ! message
   <span class="messageDate"><message:date/></span>                                     }
   <message:text/>                                                                      ...
  </div>
 </messages:list>                                                                       Listing 12 : ChatterServer.scala
</lift:comet>
...                                                                                     object ChatterServer extends LiftActor with ListenerManager with Logging {
                                                                                         private var message: ChatterMessage = _
Listing 9 : ChatterMessages.scala                                                        override def lowPriority = {
                                                                                          case message @ ChatterMessage(_, _, _, text) if !text.isEmpty => {
class ChatterMessages extends CometActor with                                              logger debug "Received Chatter message: %s".format(message)
                               CometListener with Logging {                                this.message = message
 private var messages = List[ChatterMessage]()                                             updateListeners()
 override def render = {                                                                  }
  def bindMessages(template: NodeSeq): NodeSeq = messages flatMap { m =>                 }
   bind("message", template,                                                             override protected def createUpdate = message
     "name" -> m.name,                                                                  }
     "date" -> format(m.date, boxedSessionLocale),
     "text" -> m.text)
                                                                                        Listing 13 : UserFollowingUser.scala
  }
  logger debug "Rendering messages: %s".format(messages)                                object UserFollowingUser extends UserFollowingUser
  bind("messages", defaultXml, "list" -> bindMessages _)                                  with LongKeyedMetaMapper[UserFollowingUser] {
 }                                                                                       def following_?(u: User, userId: Long) =
 override def lowPriority = {                                                             find(By(user, u), By(following, userId)).isDefined
  case message: ChatterMessage => {                                                      def findAllFollowers = User.currentUser map { u =>
   logger debug "Received Chatter message: %s".format(message)                            User findAll In(User.id, user, By(following, u))
   messages ::= message                                                                  } openOr Nil
   reRender(false)                                                                       ...
  }                                                                                     }
 }
 override def registerWith = ChatterServer                                              class UserFollowingUser extends LongKeyedMapper[UserFollowingUser]
}                                                                                         with IdPK with Logging {
                                                                                         val user = new MappedLongForeignKey(this, User) {}
Listing 10 : ChatterInput.scala                                                          val following = new MappedLongForeignKey(this, User) {}
                                                                                         ...
...                                                                                     }
ajaxForm(After(100, SetValueAndFocus(messageId, "")),
    bind("chatter", xhtml,
                                                                                        Listing 14 : ChatterMessages.scala
      "name" -> user.shortName,
      "text" -> textarea("", handleUpdate _, "id" -> messageId),                        override def shouldUpdate = {
      "submit" -> submit("Update", () => ())))                                           case ChatterMessage(userId, _, _, _) =>
...                                                                                       if (user.id.is == userId) true else following_?(user, userId)
                                                                                        }




                56 javamagazin 5|2010                                                                                                                          www.JAXenter.de
Lift-Webframework Web



     Unsere Comet-Klasse ChatterMes-
sages, dargestellt in Listing 9, kümmert
sich um das Empfangen und die Anzei-
ge der Nachrichten. Sie ist ein CometAc-
tor und ein CometListener: Mit der Me-
thode lowPriority werden eingehende
Nachrichten entgegengenommen und
threadsafe verarbeitet. Für die Anzeige
ist die Methode render verantwortlich,
die sich den Nachrichtenblock aus dem
Template schnappt und damit jede ein-
zelne Nachricht darstellt. Wie beim
Snippet weiter oben, werden die Platz-
halter durch die anzuzeigenden Daten
ersetzt, hier Absendername, Datum und
                                              Abb. 2: Chatter in Endaus-baustufe
Text der Nachricht. Durch registerWith
meldet sich unsere Comet-Klasse beim
ChatterServer (siehe unten) an.
     Nun müssen wir noch das Versen-          wir schon folgen, als auch die Möglichkeit      Menüs, Zugriffskontrolle, Persistenz,
den von Nachrichten ergänzen. Zuerst          bietet, weiteren Benutzern zu folgen. Der       Benutzerverwaltung und vieles mehr
machen wir aus unserem Eingabefor-            Vollständigkeit halber möchten wir na-          fertig zur Verfügung. Das macht klar,
mular ein Ajax-Formular, denn wir             türlich auch sehen, wer uns folgt, sodass       warum Lift heute eine herausragende
wollen nicht bei jedem Versenden einer        wir auch ein Template followers.xhtml be-       Position im Scala-Ökosystem einnimmt.
Nachricht die Seite neu laden. Dies geht      nötigen. Die Interaktionen setzen wir mit       Bleibt nur die Frage, wann Sie sich mit
mit Lift wirklich einfach (Listing 10),       dem Follow-Snippet um. Diese Templates          Lift befassen?
denn Lift abstrahiert Ajax durch ein Sca-     und dieses Snippet sind ganz ähnlich ge-
la-API. Hier umgeben wir bloß unseren         strickt wie die bisherigen, sodass wir hier
existierenden Code im ChatterInput-           auf Listings verzichten – bei Interesse bitte                Heiko Seeberger ist
Snippet mit der Methode ajaxForm, der         einfach in den Sourcecode schauen.                           geschäftsführender Gesell-
                                                                                                           schafter der Weigle Wilczek
wir zusätzlich noch ein JavaScript-Kom-            Natürlich müssen wir diese Informa-
                                                                                                           GmbH und verantwortlich
mando mitgeben, das die Textarea kurz         tionen persistieren: Die Mapper-Klasse                       für die technologische Stra-
nach dem Verschicken der Nachricht            UserFollowingUser kümmert sich um die-                       tegie des Unternehmens mit
leert.                                        se Referenzen von einem Benutzer auf an-         den Schwerpunkten Java, Scala, OSGi,
                                                                                               Eclipse RCP und Lift. Zudem ist er
     Dann müssen wir, statt nur zu loggen,    dere und das dazu gehörende Companion
                                                                                               aktiver Open Source Committer, Autor
nun tatsächlich eine Nachricht verschi-       Object bietet uns die nötigen Methoden           zahlreicher Fachartikel und Redner auf
cken. Dazu erweitern wir die handleUp-        für unser Follow Snippet bzw. die Chat-          einschlägigen Konferenzen.
date-Methode im ChatterInput-Snippet          terMessages (Listing 13). Wir erweitern          Johannes Hohenbichler ist Soft-
                                                                                               wareentwickler bei der Weigle Wilczek
(Listing 11). Wir erzeugen eine Chat-         nun noch unsere ChatterMessage um die
                                                                                               GmbH und definiert seinen technologi-
terMessage mit Absendername, Datum            ID des Absenders und teilen dem Chatter-         schen Schwerpunkt im Bereich Eclipse
und Text und schicken sie an den Chat-        Server über die Methode shouldUpdate in          RCP, OSGi, Scala und Lift.
terServer (Listing 12). Letzterer ist ein     ChatterMessages mit, ob wir eine Nach-
LiftActor und ein ListenerManager, d. h.      richt empfangen wollen: Das wollen wir
er kann Nachrichten empfangen, die er         genau dann, wenn wir selbst der Absender
an (zunächst noch) alle Listener schickt,     sind oder wenn wir dem Absender folgen            Links & Literatur
indem er updateListeners aufruft.             (Listing 14). Damit hätten wir es geschafft:       [1] http://www.twitter.com
                                              Chatter erstrahlt in voller Pracht (Abb. 2).       [2] http://liftweb.net/team.html
Persistenz mit Mapper
                                                                                                 [3] http://wicket.apache.org
OK, damit sind wir fast schon fertig. Nun     Fazit
                                                                                                 [4] http://rubyonrails.org
müssen wir Chatter nur noch so erweitern,     Dieser schnelle Überblick über einige
                                                                                                 [5] http://www.djangoproject.com
dass Nachrichten nicht an alle geschickt      der wichtigsten Features von Lift zeigt,
                                                                                                 [6] http://foursquare.com
werden, sondern nur an unsere Freunde,        wie produktiv wir mit Lift Webapplika-
                                                                                                 [7] http://incubator.apache.org/esme
d. h. diejenigen, die uns folgen. Dazu müs-   tionen entwickeln können: Es werden
                                                                                                 [8] http://it-republik.de/jaxenter/
sen wir erst einmal die Möglichkeit schaf-    nicht nur wichtige und moderne Tech-                   quickvote/results/1/poll/75
fen, anderen zu folgen, und dazu brau-        nologien wie Ajax und Comet einfach                [9] http://maven.apache.org
chen wir ein Template following.xhtml,        zugänglich gemacht, sondern es stehen             [10] http://www.h2database.com
das sowohl die Benutzer auflistet, denen      außerdem viele typische Funktionen wie




www.JAXenter.de                                                                                                    javamagazin 5|2010 57

Contenu connexe

Similaire à Java Magazin 5 / 2010 - Twitter nachgebaut mit Lift

B1 Acocon Lotus Day 08.09.2009
B1 Acocon Lotus Day 08.09.2009B1 Acocon Lotus Day 08.09.2009
B1 Acocon Lotus Day 08.09.2009Andreas Schulte
 
B3 Lotus Expeditor Und Composite Applications
B3 Lotus Expeditor Und Composite ApplicationsB3 Lotus Expeditor Und Composite Applications
B3 Lotus Expeditor Und Composite ApplicationsAndreas Schulte
 
Java magazin9 2012_wls 12c_das_dutzend_ist_voll
Java magazin9 2012_wls 12c_das_dutzend_ist_vollJava magazin9 2012_wls 12c_das_dutzend_ist_voll
Java magazin9 2012_wls 12c_das_dutzend_ist_vollWolfgang Weigend
 
Java Aktuell Bernd Zuther Canary Releases mit der Very Awesome Microservices ...
Java Aktuell Bernd Zuther Canary Releases mit der Very Awesome Microservices ...Java Aktuell Bernd Zuther Canary Releases mit der Very Awesome Microservices ...
Java Aktuell Bernd Zuther Canary Releases mit der Very Awesome Microservices ...Bernd Zuther
 
Nutzen und Anwendungspotentiale von Enterprise Wikis
Nutzen und Anwendungspotentiale von Enterprise WikisNutzen und Anwendungspotentiale von Enterprise Wikis
Nutzen und Anwendungspotentiale von Enterprise Wikispunkt. netServices
 
Systemvorstellung: dante cms im Überblick
Systemvorstellung: dante cms im ÜberblickSystemvorstellung: dante cms im Überblick
Systemvorstellung: dante cms im Überblicka3 systems GmbH
 
Web 2.0 - Überblick
Web 2.0 - ÜberblickWeb 2.0 - Überblick
Web 2.0 - Überblickeightfour
 
magnolia mit thymeleaf - ein agiler prozess-beschleuniger
magnolia mit thymeleaf - ein agiler prozess-beschleunigermagnolia mit thymeleaf - ein agiler prozess-beschleuniger
magnolia mit thymeleaf - ein agiler prozess-beschleunigerThomas Kratz
 
TYPO3 CMS 7.0 - Die Neuerungen - pluswerk
TYPO3 CMS 7.0 - Die Neuerungen - pluswerkTYPO3 CMS 7.0 - Die Neuerungen - pluswerk
TYPO3 CMS 7.0 - Die Neuerungen - pluswerkdie.agilen GmbH
 
German: Softwareprodukte aus einem Source Code mit Javascript
German: Softwareprodukte aus einem Source Code mit JavascriptGerman: Softwareprodukte aus einem Source Code mit Javascript
German: Softwareprodukte aus einem Source Code mit JavascriptRalf Schwoebel
 
Einfacher bauen
Einfacher bauenEinfacher bauen
Einfacher bauenjohofer
 
Stephan Kaps – IT-Tage 2015 – Flyway vs. LiquiBase – Battle der Datenbankmigr...
Stephan Kaps – IT-Tage 2015 – Flyway vs. LiquiBase – Battle der Datenbankmigr...Stephan Kaps – IT-Tage 2015 – Flyway vs. LiquiBase – Battle der Datenbankmigr...
Stephan Kaps – IT-Tage 2015 – Flyway vs. LiquiBase – Battle der Datenbankmigr...Informatik Aktuell
 
Entwickeln mit Wordpress
Entwickeln mit WordpressEntwickeln mit Wordpress
Entwickeln mit WordpressBlogwerk AG
 
JavaScript: Von einfachen Scripten zu komplexen Anwendungen
JavaScript: Von einfachen Scripten zu komplexen AnwendungenJavaScript: Von einfachen Scripten zu komplexen Anwendungen
JavaScript: Von einfachen Scripten zu komplexen Anwendungenmolily
 
GWT Introduction
GWT IntroductionGWT Introduction
GWT Introductionpfleidi
 

Similaire à Java Magazin 5 / 2010 - Twitter nachgebaut mit Lift (20)

B1 Acocon Lotus Day 08.09.2009
B1 Acocon Lotus Day 08.09.2009B1 Acocon Lotus Day 08.09.2009
B1 Acocon Lotus Day 08.09.2009
 
react-de.pdf
react-de.pdfreact-de.pdf
react-de.pdf
 
B3 Lotus Expeditor Und Composite Applications
B3 Lotus Expeditor Und Composite ApplicationsB3 Lotus Expeditor Und Composite Applications
B3 Lotus Expeditor Und Composite Applications
 
Java magazin9 2012_wls 12c_das_dutzend_ist_voll
Java magazin9 2012_wls 12c_das_dutzend_ist_vollJava magazin9 2012_wls 12c_das_dutzend_ist_voll
Java magazin9 2012_wls 12c_das_dutzend_ist_voll
 
Java Aktuell Bernd Zuther Canary Releases mit der Very Awesome Microservices ...
Java Aktuell Bernd Zuther Canary Releases mit der Very Awesome Microservices ...Java Aktuell Bernd Zuther Canary Releases mit der Very Awesome Microservices ...
Java Aktuell Bernd Zuther Canary Releases mit der Very Awesome Microservices ...
 
Openshift
OpenshiftOpenshift
Openshift
 
Ec2009 Templates
Ec2009 TemplatesEc2009 Templates
Ec2009 Templates
 
Nutzen und Anwendungspotentiale von Enterprise Wikis
Nutzen und Anwendungspotentiale von Enterprise WikisNutzen und Anwendungspotentiale von Enterprise Wikis
Nutzen und Anwendungspotentiale von Enterprise Wikis
 
Systemvorstellung: dante cms im Überblick
Systemvorstellung: dante cms im ÜberblickSystemvorstellung: dante cms im Überblick
Systemvorstellung: dante cms im Überblick
 
Web 2.0 - Überblick
Web 2.0 - ÜberblickWeb 2.0 - Überblick
Web 2.0 - Überblick
 
magnolia mit thymeleaf - ein agiler prozess-beschleuniger
magnolia mit thymeleaf - ein agiler prozess-beschleunigermagnolia mit thymeleaf - ein agiler prozess-beschleuniger
magnolia mit thymeleaf - ein agiler prozess-beschleuniger
 
TYPO3 CMS 7.0 - Die Neuerungen - pluswerk
TYPO3 CMS 7.0 - Die Neuerungen - pluswerkTYPO3 CMS 7.0 - Die Neuerungen - pluswerk
TYPO3 CMS 7.0 - Die Neuerungen - pluswerk
 
German: Softwareprodukte aus einem Source Code mit Javascript
German: Softwareprodukte aus einem Source Code mit JavascriptGerman: Softwareprodukte aus einem Source Code mit Javascript
German: Softwareprodukte aus einem Source Code mit Javascript
 
C5 Mashup
C5 MashupC5 Mashup
C5 Mashup
 
Einfacher bauen
Einfacher bauenEinfacher bauen
Einfacher bauen
 
Reactive Programming
Reactive ProgrammingReactive Programming
Reactive Programming
 
Stephan Kaps – IT-Tage 2015 – Flyway vs. LiquiBase – Battle der Datenbankmigr...
Stephan Kaps – IT-Tage 2015 – Flyway vs. LiquiBase – Battle der Datenbankmigr...Stephan Kaps – IT-Tage 2015 – Flyway vs. LiquiBase – Battle der Datenbankmigr...
Stephan Kaps – IT-Tage 2015 – Flyway vs. LiquiBase – Battle der Datenbankmigr...
 
Entwickeln mit Wordpress
Entwickeln mit WordpressEntwickeln mit Wordpress
Entwickeln mit Wordpress
 
JavaScript: Von einfachen Scripten zu komplexen Anwendungen
JavaScript: Von einfachen Scripten zu komplexen AnwendungenJavaScript: Von einfachen Scripten zu komplexen Anwendungen
JavaScript: Von einfachen Scripten zu komplexen Anwendungen
 
GWT Introduction
GWT IntroductionGWT Introduction
GWT Introduction
 

Java Magazin 5 / 2010 - Twitter nachgebaut mit Lift

  • 1. Web Lift-Webframework Twitter nachgebaut mit Lift Wer sich mit Scala beschäftigt, kommt an Lift nicht vorbei: Wie kaum ein anderes Produkt hat dieses innovative Webframework dazu beigetragen, das Scala-Ökosystem aufzubauen. In diesem Artikel zeigen wir anhand eines konkreten Fallbeispiels die Gründe für diesen Erfolg. von Heiko Seeberger und Johannes Hohenbichler as könnte als Vorlage besser anderen Benutzern folgen und natürlich noch unter dem Namen Scala with Sails. geeignet sein als Twitter [1]? das Nachrichtenverschicken und -an- Sein Ziel war und ist es noch heute, ein Einerseits dürfte es kaum je- zeigen unter Verwendung der Web-2.0- einfach zu benutzendes, sicheres und manden in unserer Branche geben, der Features Ajax und Comet. Doch bevor höchst produktives Webframework zu diese Art des Zwitscherns nicht kennt. wir uns die Hände schmutzig machen, schaffen. Dazu bedient sich Lift der bes- Andererseits steht Twitter trotz über- ein kurzer Überblick über Lift. ten Konzepte anderer Frameworks und schaubarem Funktionsumfang gera- ergänzt sie um eigene innovative Ideen. dezu idealtypisch für heutige moderne Von den Ursprüngen bis heute Beispiele für dieses Rosinenpicken sind Webapplikationen. Wir werden mit Im Jahr 2006 startete David Pollak [2], an Wicket [3] angelehnte Templates, Chatter – unserem Nachbau – die wich- inspiriert von vielfältigen Erfahrungen CRUD-Unterstützung wie bei Rails tigsten Features auf vereinfachte Weise mit Programmiersprachen und Frame- [4] oder Djangos [5] „More than just umsetzen: Registrieren und Anmelden, works, die Arbeit an Lift, ursprünglich CRUD“ bei der Benutzerverwaltung. 52 javamagazin 5|2010 www.JAXenter.de
  • 2. Lift-Webframework Web Heute sehen wir eine große und sehr le- Abb. 1: Initia- bendige Lift-Community mit mehr als le Startseite zehn aktiven Committern und etliche produktive Anwendungen auf Basis von Lift, z. B. Foursquare.com [6] oder ESME [7]. Derzeit befindet sich bereits die Ver- sion 2.0 in der Entwicklung, die vermut- lich auf Scala 2.8 aufsetzen wird. unter weiglewilczek.com/labs/chatter Eine Anmerkung: Selbstverständ- einen Blick auf die laufende Anwendung lich unterstützt Lift internationalisierte Ein modularer Baukasten in Endausbaustufe werfen. Einfach mit Anwendungen, aber um die Dinge noch Lift bringt als „Full Stack Framework“ E-Mail-Adresse registrieren und dann einfacher zu halten, blenden wir das hier alles mit, um eine komplette Webappli- loslegen. Zum Testen am besten mit zwei aus und halten uns konsequent an Eng- kation zu entwickeln. Dazu gehören unterschiedlichen Browsern, um die Ak- lisch. typischerweise Templates, Menüs und tualisierung der Nachrichten via Comet Zugriffskontrolle, Persistenz, CRUD- sehen zu können. Lift konfigurieren Support und eine komplette Benutzer- Den kompletten Sourcecode gibt Natürlich müss en w ir uns erer verwaltung. Aber auch ausgefallenere es unter der Eclipse Public License bei Webapplikation beibringen, dass sie Features wie PayPal-Anbindung, Open- github.com/weiglewilczek/chatter zum „geliftet“ ist, und das tun wir über ei- ID- oder OAuth-Schnittstellen sowie Browsen oder Herunterladen. Die ein- nen Servlet-Filter in web.xml. Scala ist Support für JSON-APIs werden ange- zelnen Schritte, in denen wir Chatter so flexibel und ausdrucksstark, dass boten. Doch es gibt keinen Grund, vor entwickeln werden, sind mit Tags (z. B. Lift selbst auf Konfigurationsdateien dieser Fülle an Features zu erschrecken. 0.1-template) versehen, sodass Sie die in XML verzichten kann. Stattdessen Lift ist modular aufgebaut und wir kön- Entwicklung im Sourcecode nachvoll- wird Lift in der Scala-Klasse Boot kon- nen wählen, was wir verwenden möch- ziehen können. Selbstverständlich sind figuriert, die per Default im Verzeichnis ten und was nicht. So können wir z. B. die Tickets für Fehler oder Erweiterungs- liftweb.bootstrap erwartet wird, bei uns mit lift-mapper mitgelieferte Benutzer- wünsche sehr gern gesehen. aber via Servlet-Filter-Parameter nach verwaltung verwenden oder auch eine com.weiglewilczek.chatter verschoben eigene bzw. vorhandene. Das Projekt aufsetzen ist. Neben einigen nützlichen Vorgaben Lift nutzt selbst Maven [9] und bietet für Formatierung und Internationa- Ein funktionales Framework uns mit verschiedenen Maven Arti- lisierung enthält Boot eine besonders Wozu eigentlich ein weiteres Webframe- facts eine sehr angenehme Möglichkeit, wichtige Zeile: LiftRules addToPackages work? Löst Lift unsere täglichen Aufga- unser Projekt aufzusetzen. Selbstver- getClass.getPackage. Hiermit bestim- ben anders und vor allem auch besser ständlich können wir Lift-Projekte auch men wir, dass Lift im Package com. als andere? Dank Scala: Ja. Eine kürzlich in der IDE unserer Wahl oder mit Ant weiglewilczek.chatter nach Sub-Pa- durchgeführte Umfrage auf JAXenter entwickeln, aber für Chatter bleiben ckages für Snippets und Comet-Klassen [8] hat ergeben, dass für die Leser Scala wir Maven treu, weil das einiges verein- – dazu später mehr – suchen soll. die JVM-Sprache mit dem größten Po- facht, insbesondere das Management tenzial ist. Und dieses Potenzial hebt Lift, der Abhängigkeiten. Wir verwenden Templates für das UI indem es insbesondere die funktiona- Lift 2.0-SNAPSHOT , d. h. den aktuel- Wie erstellen wir eigentlich Webseiten len Features, Traits sowie das mächtige len Entwicklungsstand für die Version mit Lift? Am einfachsten mit Templates: Typsystem von Scala nutzt. Ein gutes 2.0 sowie Maven 2.2.1. Mit dem Arti- Das sind XHTML-Seiten, die keiner- Beispiel hierfür: Wenn ein Formular- fact lift-archetype-basic erhalten wir ein lei Logik enthalten. Doch wie kommen feld übertragen oder ein Button geklickt einfaches Projekttemplate. Da wir hier dann die dynamischen Elemente auf die wird, dann soll etwas passieren, und das grundlegende CSS- und Scala-Kennt- Seite? Das funktioniert ähnlich wie bei geben wir in Lift einfach in Form von nisse voraussetzen, reichern wir unser Wicket, nur dass wir bei Lift nicht über Funktionen an. Dies entspricht viel bes- Projekt ohne weitere Erläuterungen um IDs, sondern über spezielle Elemente ser unserem intuitiven Verständnis, als ein Stylesheet sowie Hilfsklassen für mit eigenen Namespaces gehen, die so- z. B. die Kapselung in Form- und Con- die Locale-abhängige Datumsforma- zusagen als Platzhalter für den dynami- troller-Klassen, wie wir sie bei typischen tierung an. Nach ein wenig Tuning von schen Inhalt stehen. OO-Frameworks finden. POM und Projektstruktur erhalten wir unser Projekttemplate. Chatter in Action Um Chatter lokal laufen zu lassen, Listing 1 : index.xhtml Bevor wir loslegen, sollten wir uns eine genügt es, mvn jetty:run im Projektver- <lift:surround with="default" at="content"> Vorstellung davon machen, was wir im zeichnis abzusetzen. Dann können wir <div>Welcome to Chatter</div> Folgenden Schritt für Schritt entwi- unter http://localhost:8080 auf die Start- </lift:surround> ckeln. Das geht am besten, indem wir seite zugreifen (Abb. 1). www.JAXenter.de javamagazin 5|2010 53
  • 3. Web Lift-Webframework Besonders praktisch: Templates kön- lift:ChatterInput. Damit referenzieren bzw. anzumelden. Lift bringt mit dem nen verschachtelt werden. Im Verzeich- wir das Snippet ChatterInput, eine Sca- Persistenzmodul lift-mapper für relati- nis templates-hidden liegt unser „Wur- la-Klasse, die für das Dynamisieren des onale Datenbanken eine komplette Be- zeltemplate“ default.xhtml. Es enthält Inhalts zuständig ist. Im Inhalt selbst fin- nutzerverwaltung mit anpassbarem UI das HTML-Skelett für all unsere Seiten. den wir die statischen HTML-Elemente und Persistenz mit. Wir verwenden den Über ein spezielles Element aus dem lift und zwei spezielle Platzhalterelemente Trait MegaProtoUser (zugegeben, das ist Namespace definieren wir einen Anker- im chatter Namespace. Wir haben die ein komischer Name), der Attribute wie punkt, um den eigentlichen Inhalt ein- freie Wahl bei der Benennung des Name- E-Mail, Passwort, Vor- und Nachname zubinden: <lift:bind name="content"/>. spaces und müssen nur darauf achten, etc. besitzt und missbrauchen den Vor- Doch was wird dort eingebunden? dass das betroffene Snippet ihn auflöst. namen als einzigen Namen, indem wir Das ist der Inhalt aus dem Template, das Genau das tut ChatterInput in der ren- den Anzeigenamen ändern (Listing 4). wir aufrufen, also z. B. von der Seite in- der-Methode (Listing 3). Durch die Im dazugehörigen Companion dex.xhtml. Diese ist, wie in Listing 1 dar- bind-Methode werden die Elemente Object, zu dem wir den Trait MetaMe- gestellt, nur ein Fragment einer XHTML chatter:text und chatter:submit durch gaProtoUser mixen, konfigurieren wir -Seite. Mittels lift:surround geben wir die HTML-Elemente für eine Textarea unter anderem, welche Attribute wir das Template und den Ankerpunkt an, und einen Submit-Button ersetzt. Der verwenden, dass wir auf E-Mail-Validie- sodass die Willkommensnachricht in Methode textarea übergeben wir einen rung verzichten und dass die Seiten für das Default-Template eingebettet wird. leeren String als Default-Wert und eine Registrierung, Log-in etc. von unserem Funktion, die ausgeführt wird, sobald Default-Template umgeben sein sollen Interaktionen mit Snippets das Formular zum Server geschickt (Listing 5). Nun wollen wir als Erstes eine Eingabe- wird. In unserem Fall loggen wir einfach Wie aktivieren wir nun unsere Be- möglichkeit für Nachrichten schaffen, die Eingabedaten. Die Methode submit nutzerverwaltung? Indem wir in Boot d. h. wir benötigen ein Formular. Wie erwartet eine Bezeichnung für den Sub- zum einen eine Datenbankverbindung bereits erwähnt, setzt Lift zur Bearbei- mit-Button sowie ebenfalls eine Funkti- konfigurieren und zum anderen unse- tung von Formularen auf Funktionen. In on. Hier tun wir allerdings nichts. re User-Klasse mittels Schemifier.sche- unserem Fall wollen wir erst einmal nur mify in das Datenbankschema bringen die Eingabe loggen. Dazu nehmen wir Ready-to-use- (Listing 6). Das funktioniert so ähnlich ein Formular in unser Template für die Benutzerverwaltung wie in Hibernate die Einstellung ddl. Startseite auf (Listing 2). Wir umgeben Als Nächstes wollen wir uns darum küm- auto. Wir verwenden hier H2 [10] im In- den Inhalt mit dem speziellen Element mern, uns als Benutzer zu registrieren Process-Modus als Datenbank, aber lift- Listing 2 : index.xhtml Listing 5 : User.scala <lift:surround with="default" at="content"> object User extends User with MetaMegaProtoUser[User] { <lift:ChatterInput form="post"> override def signupFields = firstName :: email :: password :: Nil <div>What's happening?</div> override def skipEmailValidation = true <div><chatter:text/></div> ... <div class="right"><chatter:submit/></div> <hr/> Listing 6 : Boot.scala </lift:ChatterInput> </lift:surround> ... val dbVendor = new StandardDBVendor(Props get "db.driver" openOr "org.h2.Driver", Listing 3 : ChatterInput.scala Props get "db.url" openOr "jdbc:h2:chatter", class ChatterInput extends Logging { Props get "db.user", def render(xhtml: NodeSeq) = { Props get "db.password") { def handleUpdate(text: String) { override def maxPoolSize = Props getInt "db.pool.size" openOr 3 logger debug "Sending message: %s".format(text) } } DB.defineConnectionManager(DefaultConnectionIdentifier, dbVendor) bind("chatter", xhtml, Schemifier.schemify(true, Log infoF _, User) "text" -> textarea("", handleUpdate _), ... "submit" -> submit("Update", () => ())) } Listing 7 : Boot.scala } ... val ifLoggedIn = If(() => User.loggedIn_?, Listing 4 : User.scala () => RedirectResponse(User.loginPageURL)) class User extends MegaProtoUser[User] { val homeMenu = Menu(Loc("home", List("index"),"Home", ifLoggedIn)) override def firstNameDisplayName = "Name" val menus = homeMenu :: User.menus override def getSingleton = User LiftRules setSiteMap SiteMap(menus: _*) ... 54 javamagazin 5|2010 www.JAXenter.de
  • 4. Anzeige Agile Projekte – stabil oder fragil? Um agile Projekte zu skalieren, brauchen Teams die passenden Werkzeuge Agile Prozesse mit agilen Praktiken haben sich in vielen Projekten des Repositories herstellen. Beim Chatten erkennt das System bewährt. Zu den Erfolgskriterien agiler Projekte zählt die gelunge- automatisch Schlüsselwörter wie „Task“ oder „Story“ und erzeugt ne Zusammenarbeit. Daher sind die Teams von überschaubarer zusammen mit einer Nummer den Link zum entsprechenden Größe. Idealerweise arbeiten sie zusammen in einem Zimmer, an Work-Item. Der Chat-Partner kann diesen Link anklicken und hat einer gemeinsamen Werkbank. Aber lässt sich dieses dynamische dann ebenfalls das Work-Item auf dem Schirm. Der Chat kann im Setting auch auf andere, größere Projekte übertragen, damit der Kontext weiter gehen. Erfolg der agilen Projekte auch auf diese abstrahlt? Das Problem: Je höher man Projekte skaliert, desto weiter entfernt Eigenschaften in die IDE integrieren man sich von den bekannten Erfolgsvoraussetzungen: Das Team Dies alles ist nur dann bequem möglich, wenn all diese Eigen- ist nicht mehr überschaubar und häu g über mehrere Standorte schaften in die IDE der Entwickler eingebettet sind. Das leistet IBM verteilt. Außerdem gehören die Mitglieder oft verschiedenen Orga- Rational Team Concert durch die Integration des Clients sowohl in nisationen an, arbeiten beispielsweise bei einer Partner rma oder Eclipse als auch in Visual Studio .NET. einem Zulieferer. Continuous Integration ist eine weitere wichtige Praxis in agilen Diese Veränderung der Rahmenbedingungen führt zu Problemen in Projekten. Sie hat bei großen, verteilten Projekten eine besondere der Kommunikation und behindert die Abstimmung innerhalb des Bedeutung, denn hier können Integrationsprobleme besonders Teams. Der Informations uss ist gestört, und damit verliert man unangenehm und aufwändig werden. Daher ist ein Source-Code- einen der wichtigsten Vorteile der agilen Prozesse. Bewährte Tech- Management-System unabdingbar, das auch standortübergreifend niken wie das Arbeiten mit Taskboards funktionieren nicht mehr. einsetzbar ist. Durch ein solches System können alle Entwickler auf den Quellcode zugreifen und diesen leicht integrieren. Moderne Werkzeuge entschärfen Probleme Diese Probleme lassen sich mit modernen Werkzeugen zur agilen Bei Fehlern alten Zustand wiederherstellen Planung entschärfen. Ganz wichtig dabei ist ein gemeinsames In Rational Team Concert ndet man eine enge Verzahnung mit Repository, in dem sich alle Artefakte des Projektes be nden dem Build-Management-System. Kontinuierlich und einfach lassen und den Teammitgliedern zur Verfügung stehen. Damit sind die sich lokale und globale Builds erstellen. Bei Fehlern können die Backlogs mit ihren Stories, Epics und Tasks für alle immer sichtbar. Mitarbeiter über einen Snapshot des Repositories den alten Zu- Produktverantwortliche und Teammitglieder werden bei der Ver- stand ohne viel Aufwand wiederherstellen. waltung des Backlogs deutlich entlastet. Auch das Taskboard lässt Dieses gemeinsame Repository macht auch eine leistungsfähige sich elektronisch p egen, was den Projektfortschritt wieder für alle Verknüpfung zwischen Quellcode und Stories bzw. Work-Items sichtbar macht. Gra ken über den Zustand des Projektes wie zum möglich. Per Knopfdruck ndet man heraus, warum welche Pro- Beispiel Burndown-Charts lassen sich automatisiert erstellen und grammzeile von wem verändert wurde. Der umgekehrte Fall ist fast spiegeln immer einen aktuellen Projektstand wider. noch wichtiger: Welche Änderungen waren nötig, um eine Story zu Damit lassen sich agile Vorgehensmodelle, wie zum Beispiel realisieren oder um einen Fehler zu beheben? Nur so lassen sich Scrum, bereits sehr ef zient einsetzen. Dennoch bleibt es bei der behobene Fehler auch in mehreren Versionen sicher nachkorrigie- Fülle von Informationen für die Teammitglieder schwierig, die für sie ren. wichtigen und relevanten Informationen zu verfolgen und zu erfas- Agile Vorgehensweisen lassen sich nur skalieren, wenn den Teammit- sen. Arbeiten zum Beispiel mehrere Personen an unterschiedlichen gliedern dafür die geeigneten Werkzeuge zur Verfügung stehen. IBM Standorten an einer Story, so fällt es allen Beteiligten schwer, sich hat diese Erfahrung bei der Entwicklung von Rational Team Concert ständig zu synchronisieren. Kontinuierlich treffen im Repository selbst gemacht und genutzt. Denn das IBM-Entwicklerteam hat bei verfeinerte Anforderungen seitens der Business-Owner ein. Um der Arbeit bereits Alphaversionen des Produkts verwendet und die diese Änderungen alle zur Kenntnis zu nehmen, müssten die Team- frischen Erfahrungen nahtlos in der Weiterentwicklung und Vollen- mitglieder fortlaufend das Repository durchforsten. dung der Software umgesetzt. Dabei ist mit Rational Team Concert Viel praktischer und leichter ist es hingegen, wenn die Teammitglie- eine vollständig interaktive Entwicklungsumgebung für größere, der Änderungen im Repository per RSS-Feed erhalten. In diesem unternehmensweite Teams entstanden. Ein Werkzeug, mit dem sich Fall bekommen sie sofort eine Nachricht im eigenen Event-Log, Agilität skalieren lässt. wenn sich in der Story etwas ändert. Sie sind also immer auf dem aktuellen Stand der Informationen. Dieser Event-Log ist individu- Interesse? ell auf den Mitarbeiter zugeschnitten: Er kann selbst auswählen, über welche Veränderungen er informiert werden will. Auf diese Dann setzen Sie sich noch heute mit uns in Verbindung. Weise ießen die Informationen, die in agilen Projekten in den Daily Ansprechpartner: Werner Schoepe Stand-Ups weitergegeben werden, auch standortübergreifend. Telefon: +49-211-476-2163 E-Mail: werner.schoepe@de.ibm.com Anforderungen „just in time“ festhalten Weitere Infos und Downloads nden sich unter: www.ibm.com/software/products/de/de/rtc-standard Die Stories und Tasks spielen im Repository eine zentrale Rolle beim Informationsaustausch. Hier können die Anforderungen oder direkt auf der Community Site: „just in time“ festgehalten werden. Zusätzlich bieten sie Rubri- www.jazz.net ken für Diskussionen. So kann man im virtuellen Team Probleme und Fragestellungen gleich im Kontext der Stories erörtern. Die Treffen Sie Werner Schoepe auf der JAX 2010 – zu seinem Vortrag entsprechenden Änderungen sehen die Beteiligten sofort in ihrem „Die neue Herausforderung: Skalierung von agilen Projekten!“ Event-Log. am Montag, 3. Mai, 11:45 – 12:30 Uhr Instant Messaging ist heute an vielen Arbeitsplätzen Standard. Oder auf dem IBM-Stand. Integriert in die IDE lässt sich auch hier ein Kontext zu Objekten
  • 5. Web Lift-Webframework mapper unterstützt natürlich alle gängi- kümmert sich um Menüs und optio- cken bzw. empfangene Nachrichten gen relationalen Datenbanken. nale Zugriffskontrolle. Hier definieren anzeigen. Dazu ergänzen wir als Erstes wir das Home-Menü, sodass wir nur als unser Formular um einen Bereich zur Menüs und Zugriffskontrolle angemeldete Benutzer Zugriff haben, Anzeige der Nachrichten (Listing 8). Jetzt müssen wir dafür sorgen, dass nur sowie das Menü für die Benutzerverwal- Ähnlich wie ein Snippet, referenzieren angemeldete Benutzer Chatter verwen- tung, das wir von unserer User-Klasse wir mit dem Element lift:comet und des- den können. Dazu müssen wir erst noch quasi geschenkt bekommen. sen type-Attribut eine Klasse, die sich das Menü und die Seiten der Benutzer- um Comet kümmert. Weiter finden wir verwaltung anzeigen. Das konfigurieren Chat mit Ajax und Comet im Template einen Block mit statischen wir wiederum in Boot, indem wir eine So weit, so gut, aber das Wichtigste fehlt HTML-Elementen und Platzhaltern zur Sitemap definieren (Listing 7). Diese noch: Wir wollen Nachrichten verschi- Anzeige einer Nachricht. Listing 8 Listing 11 : ChatterInput.scala ... ... <lift:comet type="ChatterMessages"> def handleUpdate(text: String) { <messages:list> val message = ChatterMessage(user.id.is, user.shortName, now, text.trim) <div> logger debug "Sending Chatter message to server: %s".format(message) <span class="messageName"><message:name/></span> ChatterServer ! message <span class="messageDate"><message:date/></span> } <message:text/> ... </div> </messages:list> Listing 12 : ChatterServer.scala </lift:comet> ... object ChatterServer extends LiftActor with ListenerManager with Logging { private var message: ChatterMessage = _ Listing 9 : ChatterMessages.scala override def lowPriority = { case message @ ChatterMessage(_, _, _, text) if !text.isEmpty => { class ChatterMessages extends CometActor with logger debug "Received Chatter message: %s".format(message) CometListener with Logging { this.message = message private var messages = List[ChatterMessage]() updateListeners() override def render = { } def bindMessages(template: NodeSeq): NodeSeq = messages flatMap { m => } bind("message", template, override protected def createUpdate = message "name" -> m.name, } "date" -> format(m.date, boxedSessionLocale), "text" -> m.text) Listing 13 : UserFollowingUser.scala } logger debug "Rendering messages: %s".format(messages) object UserFollowingUser extends UserFollowingUser bind("messages", defaultXml, "list" -> bindMessages _) with LongKeyedMetaMapper[UserFollowingUser] { } def following_?(u: User, userId: Long) = override def lowPriority = { find(By(user, u), By(following, userId)).isDefined case message: ChatterMessage => { def findAllFollowers = User.currentUser map { u => logger debug "Received Chatter message: %s".format(message) User findAll In(User.id, user, By(following, u)) messages ::= message } openOr Nil reRender(false) ... } } } override def registerWith = ChatterServer class UserFollowingUser extends LongKeyedMapper[UserFollowingUser] } with IdPK with Logging { val user = new MappedLongForeignKey(this, User) {} Listing 10 : ChatterInput.scala val following = new MappedLongForeignKey(this, User) {} ... ... } ajaxForm(After(100, SetValueAndFocus(messageId, "")), bind("chatter", xhtml, Listing 14 : ChatterMessages.scala "name" -> user.shortName, "text" -> textarea("", handleUpdate _, "id" -> messageId), override def shouldUpdate = { "submit" -> submit("Update", () => ()))) case ChatterMessage(userId, _, _, _) => ... if (user.id.is == userId) true else following_?(user, userId) } 56 javamagazin 5|2010 www.JAXenter.de
  • 6. Lift-Webframework Web Unsere Comet-Klasse ChatterMes- sages, dargestellt in Listing 9, kümmert sich um das Empfangen und die Anzei- ge der Nachrichten. Sie ist ein CometAc- tor und ein CometListener: Mit der Me- thode lowPriority werden eingehende Nachrichten entgegengenommen und threadsafe verarbeitet. Für die Anzeige ist die Methode render verantwortlich, die sich den Nachrichtenblock aus dem Template schnappt und damit jede ein- zelne Nachricht darstellt. Wie beim Snippet weiter oben, werden die Platz- halter durch die anzuzeigenden Daten ersetzt, hier Absendername, Datum und Abb. 2: Chatter in Endaus-baustufe Text der Nachricht. Durch registerWith meldet sich unsere Comet-Klasse beim ChatterServer (siehe unten) an. Nun müssen wir noch das Versen- wir schon folgen, als auch die Möglichkeit Menüs, Zugriffskontrolle, Persistenz, den von Nachrichten ergänzen. Zuerst bietet, weiteren Benutzern zu folgen. Der Benutzerverwaltung und vieles mehr machen wir aus unserem Eingabefor- Vollständigkeit halber möchten wir na- fertig zur Verfügung. Das macht klar, mular ein Ajax-Formular, denn wir türlich auch sehen, wer uns folgt, sodass warum Lift heute eine herausragende wollen nicht bei jedem Versenden einer wir auch ein Template followers.xhtml be- Position im Scala-Ökosystem einnimmt. Nachricht die Seite neu laden. Dies geht nötigen. Die Interaktionen setzen wir mit Bleibt nur die Frage, wann Sie sich mit mit Lift wirklich einfach (Listing 10), dem Follow-Snippet um. Diese Templates Lift befassen? denn Lift abstrahiert Ajax durch ein Sca- und dieses Snippet sind ganz ähnlich ge- la-API. Hier umgeben wir bloß unseren strickt wie die bisherigen, sodass wir hier existierenden Code im ChatterInput- auf Listings verzichten – bei Interesse bitte Heiko Seeberger ist Snippet mit der Methode ajaxForm, der einfach in den Sourcecode schauen. geschäftsführender Gesell- schafter der Weigle Wilczek wir zusätzlich noch ein JavaScript-Kom- Natürlich müssen wir diese Informa- GmbH und verantwortlich mando mitgeben, das die Textarea kurz tionen persistieren: Die Mapper-Klasse für die technologische Stra- nach dem Verschicken der Nachricht UserFollowingUser kümmert sich um die- tegie des Unternehmens mit leert. se Referenzen von einem Benutzer auf an- den Schwerpunkten Java, Scala, OSGi, Eclipse RCP und Lift. Zudem ist er Dann müssen wir, statt nur zu loggen, dere und das dazu gehörende Companion aktiver Open Source Committer, Autor nun tatsächlich eine Nachricht verschi- Object bietet uns die nötigen Methoden zahlreicher Fachartikel und Redner auf cken. Dazu erweitern wir die handleUp- für unser Follow Snippet bzw. die Chat- einschlägigen Konferenzen. date-Methode im ChatterInput-Snippet terMessages (Listing 13). Wir erweitern Johannes Hohenbichler ist Soft- wareentwickler bei der Weigle Wilczek (Listing 11). Wir erzeugen eine Chat- nun noch unsere ChatterMessage um die GmbH und definiert seinen technologi- terMessage mit Absendername, Datum ID des Absenders und teilen dem Chatter- schen Schwerpunkt im Bereich Eclipse und Text und schicken sie an den Chat- Server über die Methode shouldUpdate in RCP, OSGi, Scala und Lift. terServer (Listing 12). Letzterer ist ein ChatterMessages mit, ob wir eine Nach- LiftActor und ein ListenerManager, d. h. richt empfangen wollen: Das wollen wir er kann Nachrichten empfangen, die er genau dann, wenn wir selbst der Absender an (zunächst noch) alle Listener schickt, sind oder wenn wir dem Absender folgen Links & Literatur indem er updateListeners aufruft. (Listing 14). Damit hätten wir es geschafft: [1] http://www.twitter.com Chatter erstrahlt in voller Pracht (Abb. 2). [2] http://liftweb.net/team.html Persistenz mit Mapper [3] http://wicket.apache.org OK, damit sind wir fast schon fertig. Nun Fazit [4] http://rubyonrails.org müssen wir Chatter nur noch so erweitern, Dieser schnelle Überblick über einige [5] http://www.djangoproject.com dass Nachrichten nicht an alle geschickt der wichtigsten Features von Lift zeigt, [6] http://foursquare.com werden, sondern nur an unsere Freunde, wie produktiv wir mit Lift Webapplika- [7] http://incubator.apache.org/esme d. h. diejenigen, die uns folgen. Dazu müs- tionen entwickeln können: Es werden [8] http://it-republik.de/jaxenter/ sen wir erst einmal die Möglichkeit schaf- nicht nur wichtige und moderne Tech- quickvote/results/1/poll/75 fen, anderen zu folgen, und dazu brau- nologien wie Ajax und Comet einfach [9] http://maven.apache.org chen wir ein Template following.xhtml, zugänglich gemacht, sondern es stehen [10] http://www.h2database.com das sowohl die Benutzer auflistet, denen außerdem viele typische Funktionen wie www.JAXenter.de javamagazin 5|2010 57