01.04.08

Was ist JSF überhaupt?

Auf Anfrage von Philipp, damit ihm nicht langweilig wird, jetzt wo er fertig mit seiner Arbeit ist.

Hier ein Auszug, wie er vorraussichtlich auch in der Arbeit vorkommen wird.
Wer fachliche oder Rechtschreib-Fehler findet, hinterlasse bitte einen Kommentar!

JSF

Für die Ausgabe von dynamischen HTML-Seiten eines Webservers verwendet man im Javaumfeld üblicher Weise JavaServer Pages (JSP). Damit wird die Einbettung von Javacode - und somit von dynamischem Inhalten - in HTML-Seiten ermöglicht. Die Vermischung von Java- und HTML-Code führt allerdings schnell zu einer unübersichtlichen Programmstruktur, die die Entwicklung deutlich verkompliziert.

Um die Entwicklung von Webseiten zu vereinfachen, wurden Web-Frameworks wie zum Beispiel Struts \cite{struts} oder eben JavaServer Faces (JSF) entwickelt. Beide benutzen das Model-View-Controller-Architekturmuster (MVC). In der Anwendung werden die Daten (model), die Präsentation (view) und die Programmsteuerung (controller) voneinander getrennt. JSF ist hauptsächlich für die Präsentation zuständig und verfolgt zusätzlich einen komponentenbasierten Ansatz. Bei komponentenbasierter Programmierung wird versucht die Anwendung in wiederverwendbare Komponenten zu unterteilen, um dann später diese Bausteine zu Anwendungen zusammenzusetzen.

Ein typisches Beispiel ist eine Tabelle, deren Eigenschaften in einem Objekt gespeichert sind und der man eine Liste der darzustellenden Objekte zuordnet. Diese Komponente fügt man dann in der Seite ein, immer wenn man eine Liste dieser Art verwenden möchte, anstatt den Quellcode der Tabelle selbst zu erstellen.

In dieser Arbeit wird JSF verwendet, da es im Gegensatz zu den anderen Frameworks standardisiert und Teil der Java EE 5 Spezifikation ist. JSF wird eine weite Verbreitung in Enterprise-Projekten nachgesagt und es heißt, JSF sei auch einfacher zu lernen als Struts.(siehe hierzu die Diskussion unter http://tech.groups.yahoo.com/group/novajug/message/9812)

Es gibt viele verschiedene Implementierungen und Komponenten-Bibliotheken wie zum Beispiel MyFaces von Apache, RichFaces von Exadel, ICEfaces von ICEsoft oder ADF Faces von Oracle. In dieser Arbeit wird jedoch die Referenzimplementierung von Sun verwendet, um unabhängig von Herstellern zu bleiben.

Der vollständige Verzicht auf ein Web-Framework und die Programmierung nur mit JSPs ist zwar möglich, wird aber den Möglichkeiten nicht gerecht, die man mit Java EE 5 hat.

Der Vollständigkeit halber will ich auch noch kurz Facelets erwähnen, die ich anstelle von JSP verwende:

Facelets

JSP ist darauf ausgelegt dynamische Ausgaben zu generieren. JSF verwendet JSP jedoch zur Erstellung und Verwaltung von Komponenten. Die Kombination von JSP und JSF bringt somit ein paar Schwierigkeiten mit sich. Jedoch kann man auf JSPs verzichten und statt dessen eine andere Technologie verwenden. Facelets ist eine solche Technologie und wird als Open Source Projekt unter der Aufsicht von Sun entwickelt. Die Beliebtheit des Projektes hat dazu geführt, dass über eine Aufnahme von Facelets in der zukünftigen Spezifikation JSF 2.0 (JSR 314) diskutiert wurde. Facelets werden inzwischen zwar im JSR erwähnt, aber nicht komplett übernommen.

Es ist deutlich zu erkennen, dass JSF und Facelets ein gutes Team bilden und der komplette Verzicht auf JSP viele Vorteile bringt. Facelets bieten Templating (Die Aufteilung der Webseite in einzelne Bestandteile wie zum Beispiel Header, Navigation, Content und Footer), bessere Debugmöglichkeiten durch Fehlermeldungen mit genauer Angabe der Fehlerquelle, vereinfachte Erstellung von Komponenten und noch einige andere Features. Daher wird in dieser Arbeit auf JSP verzichtet und die aktuelle Version von Facelets verwendet.

Nützliche Links:
http://java.sun.com/javaee/javaserverfaces/
http://www.jsfcentral.com/
http://www.ibm.com/developerworks/java/library/j-jsf1/
http://balusc.blogspot.com/

20.03.08

HOWTO test EJB3 with JUnit outside of the container

Since EJB 3.0, testing should be easy. And it IS much more simpler than with EJB 2.1, because you dont need to have an application server (AS) up and running

Chapter 12 in the book "Pro EJB 3: Java Persistence API" by Mike Keith and Merrick Schincariol was very useful for me.

I'm using Netbeans 6.0, EJB3, JPA and a MySQL-Datebase and i write integration tests. (as defined in the book above: focus on use-cases, decoupled from appserver, making full use of external resources such as database)

First of all i added the library JUnit (4.1) to my Netbeans-Project You can then rightclick on a sourcefile and select > Tools > Create JUnit Tests

Using the Entity Manager
If you're using the Entity Manager (EM) you must create one for your tests. Because no AS is around, you need an EM Factory and for that you need a Persistence Provider. Add the library TopLink Essentials to the project. Without the AS we cant use JTA datasource with JNDI, so i created a mysql testdatabase and added a persistence-unit for testpurposes. To use it i need the MySQL JDBC Driver-library in my project.
My persistence.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="Project-ejbPU" transaction-type="JTA">
    <jta-data-source>jdbc/project_database_jndi_name</jta-data-source>
  </persistence-unit>
  <persistence-unit name="ProjectTest-ejbPU" transaction-type="RESOURCE_LOCAL">
    <class>project.model.entity1</class>
    <class>project.model.entity2</class>
    <class>project.model.entity3</class>
    <class>project.model.entity4</class>
    <class>project.model.entity5</class>
    <properties>
        <property name="toplink.ddl-generation" value="create-tables"/>
        <property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver" />
        <property name="toplink.jdbc.url" value="jdbc:mysql://localhost:3306/project_test_db_name" />
        <property name="toplink.jdbc.user" value="root"/>
        <property name="toplink.jdbc.password" value="xxx"/>
     </properties>
  </persistence-unit>
</persistence>

Note that the transaction-type should be RESOURCE_LOCAL and not JTA, because we dont want any trouble with JNDI-stuff ;) I've been told that every entity has to be defined explicitly in the persistence.xml

Now you need to create and use the EM in your tests
Change the setUp()-method in the testclass to the following:

    @Before
    public void setUp() {
        yourbean.em = Persistence
.createEntityManagerFactory("ProjectTest-ejbPU")
.createEntityManager(); // your own setUp-stuff }
Now you can write your tests as if your app is deployed in an AS.

06.03.08

Testing Part2: Java EE

So. Nun muss ich die Test nur noch für meine Java EE-Anwendung umsetzen. Dafür nimmt man erstmal JUnit und Netbeans hilft dabei. Aber ist das wirklich eine gute Wahl? Immerhin verwende ich JSF und da gibt es andere (bessere?) Möglichkeiten. JSFUnit(beta), JunitEE, Cactus, Selenium, ... und wieder immernoch brauche ich einen JSF-Experten!

Nützliche Links:
http://www.infoq.com/news/2007/12/jsf-testing-tools
http://junit.sourceforge.net/doc/cookbook/cookbook.htm
http://www.junitee.org/

Ein gutes Netbeans-Tutorial für Netbeans habe ich nicht gefunden, aber eigentlich ist das auch nicht nötig. Legt man einen TestCase an (rechtsklick auf die Klasse, für die man den TestCase haben will > Tools > Create JUnit Tests), so kann man zwichen JUnit 3.x oder 4.x wählen, dann noch welche Tests man haben will und die Tests werden im TestPackage erstellt. Also im Prinzip hat man hier - wie bei Rails - Testdummies, die man dann reparieren muss. Das mache ich dann jetzt mal.

Soweit so gut. Allerdings sind diese erstmal nur fürs Backend. Um die WebApp zu testen bräuchte ich HttpUnit oder ähnliches.

UPDATE: Soweit gar nicht gut, weil man nicht einfach EJBs testen kann, da diese ja im AppServer laufen müssen. Man muss also einen Testdienst implementieren, der dann tests in der deployten Anwendung ausführen kann. Oder man nimmt JUnitEE oder Cactus oder...?? Ich finde es erstaunlich wie wenig sinnvolle Hilfe man zu diesem Thema findet. EJBs testen sollte doch eigentlich ziemlich wichtig sein.... Zitat: "Although this [JUnit Testing] works well for most standalone applications, it becomes outrageously complicated when you test code -- like an EJB -- that runs in an application server."

btw: Den Fehler im Rails-Testing habe ich immernoch nicht gelöst. Siehe Blogeintrag von gestern. Bin über Kommentare dankbar.

05.03.08

Testing Part1: Rails

Bisher habe ich mich davor gedrückt Tests zu schreiben, aber da komme ich nicht länger drumherum.

Das sinnvollste wird wohl sein, alles was ich von Hand teste, mit automatische Tests abzudecken. Customer und Rating anlegen, Fakten eintragen, löschen, usw...

Da ich mich mit Tests noch nicht so auskenne, fange ich dieses Mal mit Rails an, da hier der Einstieg ins Testing einfacher scheint.
Hier erstmal ein paar nützliche Links:
http://manuals.rubyonrails.com/read/book/5
http://nubyonrails.com/articles/ruby-rails-test-rails-cheat-sheet

Nun bringt ein Blick in das Buch "The Railsway" doch Zweifel, ob ich nicht besser das plugin RSpec zum Testen verwenden sollte. So würde ich damit den eigentlichen vorgesehenen Weg von Rails verlassen und das sollte in meinem Vergleich eigentlich nicht passieren. Ich werde mich also mit den mitgelieferten Testmöglichkeiten auseinandersetzen.

Rails hat automatisch schon einige Tests angelegt und da dort zB die später hinzugefügte Validierung noch nicht berücksichtigt wird, bekam ich beim ersten Durchlauf auch jede Menge Fehler.

Die habe ich jetzt repariert, aber es bleiben 2 Tests übrig, die einfach nicht funktionieren wollen. Da brauche ich mal eure Hilfe, denn ich komme einfach nicht weiter...

Also... Hier ein Test, der funktioniert:

def test_should_destroy_rating
assert_difference('Rating.count', -1) do
delete :destroy, :id => ratings(:one).id
end
assert_redirected_to ratings_path
end

Die Fixture dazu:

one:
date: 2008-01-10 02:30:05
rating: 5000
status: COMPLETED
customer: one

Die DB-Tabelle sieht so aus:

create_table :ratings do |t|
t.datetime :date
t.integer :rating
t.string :status
t.references :customer
t.timestamps
end

Alles wunderbar und jetzt der Test, der nicht funktioniert:

def test_should_destroy_fact_type
assert_difference('FactType.count', -1) do
delete :destroy, :id => fact_types(:fact_type_1).id
end
assert_redirected_to fact_types_path
end

Die Fixture dazu (im moment als csv, habe es aber auch schon als yaml gehabt. gleicher fehler:

id,factCategory_id,title,question,question_type
1,2,"Alter des Kunden","Wie alt ist der Kunde?","FREE"

Die DB-Tabelle sieht so aus:

create_table :fact_types do |t|
t.string :title
t.text :question
t.string :question_type
t.references :factCategory
t.timestamps
end

Die Fehlermeldung ist:

MySQL Error: #42S22Unknown column 'facts.fact_type_id' in 'where clause': SELECT * FROM `facts` WHERE (facts.fact_type_id = 1)

Das kann auch nicht funktionieren, weil anstatt "fact_type_id" müsste rails einfach nur die column "id" in der where-clause verwenden. Beim rating klappt das doch auch!? Warum hier nicht? Den einzigen Unterschied den ich sehe ist der Unterstrich im Tabellennamen...
Was übersehe ich?

20.02.08

Aufbau der Arbeit

Ein Überblick ist nie verkehrt und hier folgt einer über den Aubau meiner Arbeit also known as kommentiertes Inhaltverzeichnis:

  1. Einleitung
    1. Motivation
      Warum mache ich das Ganze?
    2. Problemstellung
      Und wo liegt das Problem?
    3. Aufbau
  2. Grundlagen
    1. Web Engineering
    2. Metriken
      Was sind Metriken und welche verwende ich?
    3. Programmiersprachen
      Wo gibt es Unterschiede und warum ist das relevant?
  3. Die Entwicklungsumgebungen
    1. Java EE
      1. Java
        Hauptmerkmale der Sprache
      2. Zielsetzung
        Wozu ist JavaEE gedacht?
      3. Konzept
        Hier wird auf den Application Server eingegangen
      4. Komponenten
        Hier werden die Komponenten beschrieben, die ich verwende
      5. Werkzeuge
        ...und hier die Werkzeuge (Netbeans)
    2. Ruby on Rails
      1. Ruby
        Hauptmerkmale der Sprache
      2. Zielsetzung
        Was will Rails erreichen?
      3. Komponenten
        Welche Komponenten beinhaltet Rails?
      4. Struktur
        MVC und so
      5. Werkzeuge
        Aptana/Konsole/Vielleicht ein Blick auf Netbeans
    3. Ein erster Vergleich
      Ausarbeitung der markantesten Unterschiede. Bewertung aber erst in Kapitel 5
  4. Beispielanwendung
    1. Rating
      Was ist überhaupt ein Rating?
    2. Grundversion
      1. Anforderungen
      2. Vorarbeiten
        Datenmodellierung
      3. Umsetzung
        Hier ist noch offen, wie der Abschnitt aussehen soll. s.u.
    3. Erste Erweiterung
      1. Anforderungen
      2. Umsetzung
    4. Zweite Erweiterung
      1. Anforderungen
      2. Umsetzung
  5. Auswertung
    1. Metriken
      Die gesammelten Daten werden analysiert
    2. Besondere Aspekte
    3. Eindruck
      subjektive Bewertung
  6. Fazit
    1. Zusammenfassung
    2. Fazit
    3. Ausblick

Je nach Zeit sind auch noch mehrere Iterationen denkbar.
Bei dem Abschnitt "Umsetzung" ist noch unklar, ob ich besser zuerst die Umsetzung in JavaEE und dann in Rails beschreiben soll oder einzelne Punkte nehmen soll wie zB Validierung und jeweils beschreibe wie es in beiden umgesetzt wird. Dann springt man immer hin und her zwischen Rails und JavaEE, aber hat dafür einen direkteren Vergleich. Was meint ihr ist für den Leser besser?

Das letzte Kapitel heißt "Fazit" und ein Abschnitt darunter auch "Fazit". Fällt jemandem ein besserer Titel für eins von beiden ein?

06.02.08

Vom Schreiben und Texten

Zur Zeite schreibe ich so gut es geht alles Bisherige zusammen. Die Grundlagen (ruby&java, rails&javaee, web-engineering, metriken, usw) und die Erkenntnisse aus der Programmierung der Grundversion auszuformulieren ist garnicht so einfach. Ich dachte, ich schreibe das einfach so runter, aber es zieht sich alles sehr und ich komme nicht so schnell voran, wie ich das gerne hätte. Aber wann ist das auch schon der Fall.. ;)

Jedenfalls habe ich inzwischen einige Absätze geschrieben und die Struktur der Arbeit nimmt langsam Formen an. Ich weiß jetzt nicht, wie ich das hier oder am Freitag zeigen kann. Vielleicht poste ich einfach mal das Inhaltsverzeichnis oder so.

Nebenbei habe ich in der Rails-Version die Validierung reingesetzt und vielleicht errinnert sich noch einer, dass ich mich bei JSF gefreut hatte, dass es so einfach ist, einen Validator zu schreiben. Tja im Vergleich zu Rails ist es bei JSF aber immernoch fürchterlich umständlich und auch logisch wirds an die falsche Stelle programmiert - nämlich in die view anstatt ins model.

Außerdem habe ich endlich den Destroy-Bug behoben. Die Lösung besteht darin, nicht den Fact direkt zu speichern, sondern den Fact im Rating zu ändern und dann das Rating abzuspeichern, wodruch dann mit dem cascading auch der Fact abgespeichert wird. Aber wie schon vor einiger Zeit gesagt, würde ich da gerne mal ein längeres Gespräch mit einem JavaEE/JSF-Profi reden um herauszufinden ob das denn alles so seine Richtigkeit hat, wie ich das programmiere...

Am Freitag habe ich Halbzeit und dann sollte ich auch mal mit der zweiten Iteration anfangen. Ich bin meiner Meinung nach nicht in der Zeit und brauche mehr Motivation/Arschtritte.... Nur zu!

30.01.08

API gefällig?

Ich habe gerade http://www.gotapi.com entdeckt und finde es großartig!
Einfach ausprobieren!

22.01.08

Wie es ist und wie es sein sollte...

Das schwierigste an Rails ist mitunter, dass man es "schön" machen will, dem "Rails-way" entsprechend. So gibt es ein paar Sachen, die kann man irgendwie programmieren, aber die man natürlich einfach und elegant lösen will. So wie es sein sollte. Da kann man dann auch schonmal gut Zeit mit Suchen nach der besten Lösung verbringen...

Wie ihr wisst, arbeite ich gerade an der Rails-Version der Anwendung und da ich ganz gut voran kam, habe ich in den letzten Tagen nicht wirklich intensiv gearbeitet. Aber der Counter da rechts zählt unbarmherzig weiter runter, also Schluss mit lustig und weiterarbeiten.

Für "Pagination" (gibts da ein anständiges deutsches Wort für?) verwende ich das plugin will_paginate und das funktioniert auch einwandfrei. Ich frage mich jedoch wie ich damit eine Collection "paginaten" kann, die nicht als Abfrage aus der Datenbank kommt. Geht das? Anscheinend baut will_paginate auf find(:all) auf und verändert nur das Array so, dass es auch Informationen zu aktuellen Seite enthält.

Interessanter Weise habe ich ein paar Dinge entdeckt, die man in JavaEE konfigurieren konnte und ich in Rails selber programmieren muss außer es gibt ein plugin... (oder gibts nen Trick/"Rails-way"?)
Gibt es zum Beispiel in Rails etwas äquivalentes zu der Angabe der Customer-Rating-Beziehung "@OneToMany(cascade = CascadeType.REMOVE ...."? D.h. wenn ich einen Customer lösche, werden automatisch auch alle Ratings zu diesem Customer gelöscht.
In Rails würde ich jetzt in der destroy-Methode im customer-controller dafür sorgen, dass auch alle Ratings gelöscht werden. Gibt es einen eleganten Weg dies zu erledigen, oder muss ich tatsächlich jedes Rating (und dann natürlich auch jeden Fact eines Ratings) durchgehen und löschen?

(Nochmal grob zur Erinnerung: customer -hasmany-> ratings -hasmany-> facts -belongsto-> factType)

Ein anderes Problem ist zur Zeit die Umsetzung der Rating-Detail-Ansicht. Hier hatte ich in JavaEE eine Liste aller Fakttypen angelegt und dann angezeigt ob in diesem Rating der Fakt eingetragen wurde oder noch leer ist. (Dort hatte ich die Collection von Facts des Ratings aus der Datenbank und habe dann für alle nicht vorhandenen FactTypen Einträge hinzugefügt. Die Darstellung der überarbeiteten Collection samt pagination hat dann die entsprechende JSF-Komponente übernommen.)

Tja, wie löse ich das jetzt mit Rails? Insbesondere mit pagination? Ich bräuchte im Prinzip alle facts des ratings und dies mit einem right outer join verknüpft mit fact_types. Also so, dass von jedem FactType ein Fact für das Rating aufgelistet wird, ob es nun schon eingetragen ist oder nicht. (deshalb outer join)
Ob das nun verständlich war, wage ich zu bezweifeln.
Aber ich habe eine Idee und werde das auch sogleich mal angehen...

18.01.08

Rails 2.0 ftw

Nachdem ich in JavaEE zu kämpfen hatte, ist Rails doch irgendwie angenehmer. Manchmal muss man suchen, wie man das dem-"rails-way"-entsprechend zu machen hat. Aber wenn man das dann gefunden hat, wie der Befehl heißt oder wo was wie heißen muss, damit einfach alles sofort geht, dann ist es auch logisch und man kann es sich gut merken.
Jedenfalls ist das Erstellen eines ersten Prototypen um einiges leichter - besonders mit scaffold.
Sehr geholfen hat mir dabei das Rails 2.0 Scaffold Tutorial Rolling-with-Ruby-on-Rails-Revised. Leider muss man sich für den Download anmelden, aber das war es mir wert. ;)

Das Design anzupassen war auch nicht schwer und so sehen beide Anwendungen sich schon sehr ähnlich. Wie ich die Navigation in Rails vernünftig definiere muss ich noch rausfinden, aber ich errinnere mich dunkel, dass das relativ einfach war.

Es macht auf jeden Fall mehr Spaß, aber gerade deshalb verliere ich grade zusehens an Disziplin. Wenn man mehr in weniger Zeit schafft, kann man sich die restliche Zeit ja auch frei nehmen... *hust* Gefährliches Spiel....

09.01.08

Käferplage

Ein Bug behoben, da hat sich schon der nächste eingenistet....

Wird etwas gelöscht oder hinzugefügt, gibt es jetzt keine Inkonsistenzen mehr zwischen EJB und Webapplication, was mich allerdings einen Datenbankaufruf mehr kostet, der IMHO eingespart werden könnte. Zur Zeit weiß ich aber keine bessere Lösung.
Doch nun tritt folgender Fehler auf: Erstelle ich ein Rating und gebe dazu ein paar Facts ein, kann ich das Rating nicht mehr löschen. Die Datenbank meckert, obwohl ich Cascading an habe. Wenn ich zuerst die Facts lösche, dann das Rating klappt es. Das war zu erwarten. Aber richtig merkwürdig wird es, wenn ich die Anwendung neu starte. Dann kann ich das Rating löschen, zusammen mit allen dazugehörigen Facts.