Donnerstag, 28. November 2013

AppFuse: setup and first start

Neulich bin ich auf der Suche nach einem Single-Page-(Web-)Application-Framework auf die empfehlenswerten Präsentationen von Matt Raible gestoßen. Dabei entdeckte ich, dass er der Gründer von AppFuse ist. AppFuse stellt sich mir als eine Art Template-Mechanismus zum schnellen Aufsetzen eines kompletten Applikationsstacks dar. Und da gerade ein neues Projekt ansteht, wollte ich mal schauen, ob das alles tatsächlich so einfach geht wie versprochen.

Also schnell die AppFuse-QuickStart-URL aufgerufen und einen Stack ausgewählt. Die Vorbedingung JDK und Maven sind auf meinem Entwicklungsrechner Grundvoraussetzungen. Blieb noch MySQL und ein SMTP-Server. Da das erst einmal ein Test sein soll und weitere Datenbankprofile versprochen wurden, habe ich mich für die Memory-Datenbank "H2" entschieden. Auf eMail habe ich erst einmal ganz verzichtet. AppFuse empfiehlt den Einsatz von Apache-James. Das probiere ich, wenn der Rest vielversprechend aussieht.



Für den Test habe ich die aussagekräftige GroupID "org.test" und die ArtifactId "app" verwendet. Die Version ist mit 2.2.1 die letzte freigegebene. Von den angebotenen Web-Framewoks habe ich mit JSF die meisten Erfahrungen. Also habe ich mich dafür entschieden. Und weil ich immer noch mit dem Gedanken einer Single-Page WebApp liebäugele wählte ich das "Multi-Module-Projekt". Damit wird getrennt ein Core- und ein Web-Module generiert. Das ergab folgendes Maven-Kommando:

mvn archetype:generate -B -DarchetypeGroupId=org.appfuse.archetypes -DarchetypeArtifactId=appfuse-modular-jsf-archetype -DarchetypeVersion=2.2.1 -DgroupId=org.test -DartifactId=app -DarchetypeRepository=http://oss.sonatype.org/content/repositories/appfuse


Nach ca. 32 Sek. erschien folgende Erfolgsmeldung:

[INFO] --------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] --------------------------------------------------------------
[INFO] Total time: 32.198s
[INFO] Finished at: Tue Nov 26 13:32:09 CET 2013
[INFO] Final Memory: 17M/147M
[INFO] --------------------------------------------------------------


Entstanden ist jetzt folgende Verzeichnisstruktur:

.
|-- core
|   |-- src
|   |   |-- main
|   |   |   |-- java
|   |   |   `-- resources
|   |   `-- test
|   |       |-- java
|   |       `-- resources
|   `-- target
|       |-- appfuse-root
|       |   |-- appfuse-data
|       |   `-- appfuse-service
|       |-- classes
|       |   |-- META-INF
|       |   `-- org
|       |-- generated-sources
|       |   `-- annotations
|       |-- generated-test-sources
|       |   `-- test-annotations
|       `-- test-classes
|           `-- org
|-- src
|   `-- site
|-- target
|   `-- appfuse-root
`-- web
    |-- src
    |   |-- main
    |   |   |-- java
    |   |   |-- resources
    |   |   `-- webapp
    |   |-- site
    |   `-- test
    |       |-- java
    |       `-- resources
    `-- target
        `-- appfuse-root
            `-- appfuse-web


Die Quickstart-Anleitung ermöglicht jetzt einen Wechsel vom sogenannten "embedded mode" in den "full source mode". Der Unterschied ist, dass im embedded mode der Service Layer nur binär in JARs vorliegt. Da ich aber den generierten Code sehen möchte, schalte ich erst einmal in den full source mode um:

#> cd app
#> mvn appfuse:full-source


Das dauerte schon ewtas länger, ca. 2 Min.:

[INFO] --------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] --------------------------------------------------------------
[INFO] Total time: 2:00.102s
[INFO] Finished at: Tue Nov 26 13:41:43 CET 2013
[INFO] Final Memory: 12M/122M
[INFO] --------------------------------------------------------------


Jetzt soll die Applikation natürlich gestartet werden. Normalerweise soll das einfach mittels Aufruf von "mvn jetty:run" im root-Verzeichnis des Projektes funktionieren. Aber da ich mich für ein "Multi-Module-Projekt" entschieden habe, muss ich laut Quickstart-Anleitung zuerst das Core-Module installieren:

#> cd core
#> mvn install


Hier kommt es nach ca. 26 Sek. zu einem Fehler:

[INFO] --------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] --------------------------------------------------------------
[INFO] Total time: 26.463s
[INFO] Finished at: Tue Nov 26 13:46:00 CET 2013
[INFO] Final Memory: 24M/162M
[INFO] --------------------------------------------------------------
[ERROR] Failed to execute goal org.codehaus.mojo:dbunit-maven-plugin:1.0-beta-3:operation (test-compile) on project app-core: Error executing database operation: CLEAN_INSERT: Communications link failure
[ERROR] 
[ERROR] The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server. Verbindungsaufbau abgelehnt
[ERROR] -> [Help 1]


Die Ausgaben ein wenig hochgescrollt, erschließt sich auch schnell der Fehler:

ERROR - SchemaExport.execute(274) | schema export unsuccessful
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
 at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)


Die Datenbank sollte aufgebaut werden und dazu wurde eine MySQL Datenbank gesucht. Aber ich wollte ja H2 verwenden und habe das nirgendwo angegeben. Ein Blick in die bereits oben erwähnten Datenbankprofile zeigt, dass der Parameter "-Ph2" fehlt. Also auf ein Neues:

#> mvn -Ph2 install


Jetzt war die Installation des Core-Moduls nach ca. 1:40 Min. erfolgreich.

[INFO] --------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] --------------------------------------------------------------
[INFO] Total time: 1:40.385s
[INFO] Finished at: Tue Nov 26 17:08:08 CET 2013
[INFO] Final Memory: 15M/159M
[INFO] --------------------------------------------------------------


Fehlt nur noch, die Webapplikation zu starten. Normalerweise muss nur der Befehl "mvn jetty:run" im root-Verzeichnis des Projektes gestartet werden. Da ich aber eine "Multi-Module-Projekt" habe, muss ich den Befehl im Web-Ordner des Projektes ausführen. Hinzu kommt bestimmt auch noch das Datenbankprofil für die H2-DB:

#> cd ..
#> cd web
#> mvn -Ph2 jetty:run


Leider gab es nach nur 8 Sekunden folgenden Fehler:

[INFO] --------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] --------------------------------------------------------------
[INFO] Total time: 8.712s
[INFO] Finished at: Tue Nov 26 17:20:25 CET 2013
[INFO] Final Memory: 10M/86M
[INFO] --------------------------------------------------------------
[ERROR] Failed to execute goal on project app-web: Could not resolve dependencies for project org.test:app-web:war:1.0-SNAPSHOT: Failed to collect dependencies for [com.h2database:h2:jar:1.3.170 (compile), org.test:app-core:jar:1.0-SNAPSHOT (compile), com.ocpsoft:prettyfaces-jsf2:jar:3.3.3 (compile), com.sun.facelets:jsf-facelets:jar:1.1.14 (compile), commons-dbcp:commons-dbcp:jar:1.3 (compile), commons-io:commons-io:jar:2.0.1 (compile), commons-lang:commons-lang:jar:2.6 (compile), javax.el:el-api:jar:1.0 (test), javax.servlet:servlet-api:jar:2.5 (provided), javax.servlet:jstl:jar:1.2 (compile), javax.servlet.jsp:jsp-api:jar:2.1 (provided), junit:junit:jar:4.10 (compile?), log4j:log4j:jar:1.2.17 (compile), net.java.dev.ajax4jsf:ajax4jsf:jar:1.0.6 (compile), net.sf.ehcache:ehcache-web:jar:2.0.4 (compile), net.sf.ehcache:ehcache-core:jar:2.6.2 (compile), net.sourceforge.jsf-comp:acegi-jsf:jar:1.1.3 (compile), opensymphony:sitemesh:jar:2.4.2 (compile), org.apache.myfaces.core:myfaces-api:jar:2.1.9 (compile), org.apache.myfaces.core:myfaces-impl:jar:2.1.9 (compile), org.apache.myfaces.tomahawk:tomahawk20:jar:1.1.10 (compile), org.apache.shale:shale-test:jar:1.0.5 (compile?), org.aspectj:aspectjweaver:jar:1.6.10 (compile), org.aspectj:aspectjrt:jar:1.6.10 (compile), org.directwebremoting:dwr:jar:2.0.3 (compile), org.slf4j:slf4j-api:jar:1.6.1 (compile), org.slf4j:jcl-over-slf4j:jar:1.6.1 (compile), org.slf4j:slf4j-log4j12:jar:1.6.1 (compile), org.springframework:spring-test:jar:3.1.3.RELEASE (compile?), org.springframework:spring-aop:jar:3.1.3.RELEASE (compile), org.springframework:spring-webmvc:jar:3.1.3.RELEASE (compile), org.springframework.security:spring-security-core:jar:3.1.3.RELEASE (compile), org.springframework.security:spring-security-config:jar:3.1.3.RELEASE (compile), org.springframework.security:spring-security-taglibs:jar:3.1.3.RELEASE (compile), org.subethamail:subethasmtp-wiser:jar:1.2 (test), org.tuckey:urlrewritefilter:jar:3.1.0 (compile), struts-menu:struts-menu:jar:2.4.3 (compile), junit:junit-dep:jar:4.5 (test), org.jmock:jmock:jar:2.5.1 (compile?), org.jmock:jmock-junit4:jar:2.5.1 (compile?)]: Failed to read artifact descriptor for org.test:app-core:jar:1.0-SNAPSHOT: Could not find artifact org.test:app:pom:1.0-SNAPSHOT in appfuse-snapshots (http://oss.sonatype.org/content/repositories/appfuse-snapshots) -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/DependencyResolutionException


Der letzte root cause der Ausgabe des vollständigen Maven Debug-Logs sah so aus:

Caused by: org.sonatype.aether.transfer.ArtifactNotFoundException: Failure to find org.test:app:pom:1.0-SNAPSHOT in http://oss.sonatype.org/content/repositories/appfuse-snapshots was cached in the local repository, resolution will not be reattempted until the update interval of appfuse-snapshots has elapsed or updates are forced
 at org.sonatype.aether.impl.internal.DefaultUpdateCheckManager.newException(DefaultUpdateCheckManager.java:230)
 at org.sonatype.aether.impl.internal.DefaultUpdateCheckManager.checkArtifact(DefaultUpdateCheckManager.java:204)
 at org.sonatype.aether.impl.internal.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:427)
 ... 40 more


Die Webapp kann also die Core-App nicht im Artifact Repository finden - obwohl ich ein Install der Core-App durchgeführt habe. Die Core-App befindet sich auch korrekt im lokalen Maven-Cache-Repository, welches laut Maven-Doku immer zuerst verwendet wird, auch wenn das nicht in der pom.xml deklariert wurde.

#> tree .m2/repository/org/test/
.m2/repository/org/test/
|-- app
|   `-- 1.0-SNAPSHOT
|       |-- app-1.0-SNAPSHOT.pom.lastUpdated
|       `-- resolver-status.properties
`-- app-core
    |-- 1.0-SNAPSHOT
    |   |-- app-core-1.0-SNAPSHOT.jar
    |   |-- app-core-1.0-SNAPSHOT.pom
    |   |-- maven-metadata-local.xml
    |   `-- _maven.repositories
    `-- maven-metadata-local.xml


Trotz langem Suchen fand ich keine wirkliche Ursache und vor allem auch keine Lösung für diesen Fehler. Letztendlich hat mein Spieltrieb eine mögliche Lösung gefunden. Der Aufruf der übergeordneten pom.xml im root-Verzeichnis des Projektes half:

#> cd ..
#> ls
core  pom.xml  README.txt  src  target  web
#> mvn -Ph2


Nach ca. 7:14 Min. gab es folgendes widersprüchliches Ergebnis:

[INFO] --- webtest-maven-plugin:1.0.0:verify-result (webtest-verify) @ app-web ---
[INFO] --------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] AppFuse JSF Application ........................... SUCCESS [1.122s]
[INFO] AppFuse Modular Application - Core ................ SUCCESS [1:00.775s]
[INFO] AppFuse Modular Application - Web (JSF) ........... FAILURE [6:10.748s]
[INFO] --------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] --------------------------------------------------------------
[INFO] Total time: 7:14.213s
[INFO] Finished at: Tue Nov 26 17:59:45 CET 2013
[INFO] Final Memory: 82M/296M
[INFO] --------------------------------------------------------------
[ERROR] Failed to execute goal org.codehaus.mojo:webtest-maven-plugin:1.0.0:verify-result (webtest-verify) on project app-web: There were test failures : 1/13 -> [Help 1]


Nichts desto trotz wollte ich mal schauen, ob die Webapp jetzt startet.

#> cd web
#> mvn -Ph2 jetty:run


Und siehe da, nach weiteren gefühlten 20 Sek. kam folgende Asugabe:

DEBUG [main] LocaleFilter.init(172) | Initializing filter 'localeFilter'
DEBUG [main] LocaleFilter.init(197) | Filter 'localeFilter' configured successfully
2013-11-26 18:04:26.739:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server


Und eine Eingabe der URL "http://localhost:8080" brachte den ersehnten Startbildschirm:



Welche Möglichkeiten die neue Appfuse-App bietet und wie diese umgesetzt sind, schaue ich mir im nächsten Post an.

Aus Neugier habe ich mir jetzt nochmals den lokalen Maven-Cache angeschaut:

#>tree .m2/repository/org/test/
.m2/repository/org/test/
|-- app
|   |-- 1.0-SNAPSHOT
|   |   |-- app-1.0-SNAPSHOT.pom
|   |   |-- app-1.0-SNAPSHOT.pom.lastUpdated
|   |   |-- maven-metadata-local.xml
|   |   |-- _maven.repositories
|   |   `-- resolver-status.properties
|   `-- maven-metadata-local.xml
`-- app-core
    |-- 1.0-SNAPSHOT
    |   |-- app-core-1.0-SNAPSHOT.jar
    |   |-- app-core-1.0-SNAPSHOT.pom
    |   |-- maven-metadata-local.xml
    |   `-- _maven.repositories
    `-- maven-metadata-local.xml


Auffällig sind die zusätzlichen Dateien im Ordner "app/1.0-SNAPSHOT". Wenn ich jetzt nochmals die obige Fehlermeldung anschaue, dann steht dort auch, dass Maven das Artefakt "org.test:app:pom:1.0-SNAPSHOT" nicht finden konnte. Da steht nichts von Core. Da habe ich wohl etwas flüchtig gelesen. Und die Quickstart-Anleitung von AppFuse scheint auch ein wenig ungenau zu sein - zumindest für ein "Multi-Module-Projekt". Ungeachtet dessen habe ich nach kurzer Zeit (ignorieren wir mal die Fehlersuche) einen kompletten und lauffähigen Applikationsstack.

Keine Kommentare:

Kommentar veröffentlichen