Archiv der Kategorie: maven

Spring, Wicket und die GAE

Im letzten Artikel haben wir ein initiales Setup einer Wicket-Applikation für die Google App Engine vorgenommen. Die Applikation ist nach wie vor hier erreichbar.

In diesem Artikel wollen wir die Applikation springifizieren, d.h. wir wollen das Springframework integrieren.

Zunächst definieren wir folgende pom im Unterverzeichnis „dependencies/spring“.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>de.effective</groupId>
    <artifactId>spring-dependencies</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>spring-dependencies</name>
    <description>spring dependencies</description>

    <properties>
       <spring.version>3.1.1.RELEASE</spring.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-tx</artifactId>
                <version>${spring.version}</version>
            </dependency>
       </dependencies>
</project>

Spring definiert mittlerweile sehr viele Projekte, diese pom kann einfach importiert werden und theoretisch auch in anderen Projekten importiert werden.

Folgendes Fragment importiert die Spring-Abhängigkeiten (definiert in der ui-pom).


<dependency>
<groupId>de.effective</groupId>
<artifactId>spring-dependencies</artifactId>
<version>1.0-SNAPSHOT</version>
<type>pom</type>
</dependency>

Wichtig ist hier das <type>pom</type>-Tag, denn hierdurch werden die in der spring-pom definierten Abhängigkeiten so aufgelöst als wären sie hier direkt in der pom definiert.

Zusätzlich deklarieren wir das Spring-Dependencies-pom im Application-Reactor-Pom:


<modules>
<!--adding-->
<module>wicketstuff/jdk-1.6-parent/gae-initializer-parent/gae-initializer</module>
<module>dependencies/spring</module>
<module>ui</module>
</modules>

Um zu testen, ob die Spring-Integration funktioniert wollen wir jetzt einfach die Erzeugung der Wicket-Application-Instanz über Spring steuern.

Hierfür müssen wir die web.xml des Projektes anpassen. In dieser ist aktuell folgendes definiert.


<filter>
<filter-name>wicket.effectivetrainings.de</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationClassName</param-name>
<param-value>de.effective.EffectiveApplication</param-value>
</init-param>
</filter>

Das muss abgeändert werden in:


<filter>
<filter-name>wicket.effectivetrainings.de</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationFactoryClassName</param-name>
<param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
</init-param>
</filter>

Wir registrieren also nicht die Applikation selbst, sondern eine Factory, die die Applikation über Spring auflöst. (Das ist eigentlich der Standardweg um damit zu arbeiten).

Zusätzlich müssen wir sicherstellen, dass der spring-context beim Starten der Applikation geladen wird.

Das kann auch in der web.xml passieren und zwar über den Standardmechnismus eines ContextLoaderListeners.


<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Damit Spring weiß, wo es seinen Kontext findet, muss noch folgender Parameter definiert werden.

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-context.xml</param-value>
</context-param>

Als nächstes definieren wir uns einen sehr einfachen Spring-Context:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:component-scan base-package="de.effective"/>
</beans>

Spring sucht im Package de.effective und allen Unterverzeichnissen nach Annotierten Spring-Beans.

Zuletzt definieren wir unsere Wicket-Applikation als SpringBean.


@Component
public class EffectiveApplication extends WebApplication
{

...

}

Wir deployen die Applikation und greifen darauf zu.

 

 

 

 

 

 

Das Projekt ist weiterhin auf github gehostet. Der Commit der diese Anforderung implementiert ist hier zu finden. Das Projekt als Zip gibt es hier.

https://github.com/dilgerma/effectivetrainings/commit/3dc99d3c88cf343cfbfbcf5ad7b88069c036d4ad

Lokale Maven Artefakte löschen und neu beziehen

Oft wichtig zu wissen, ob das Projekt noch baut auch ohne die Artefakte im lokalen Repository.


mvn dependency:purge-local-repository -DreResolve=false -DactTransitively=true -Dverbose=true clean install

Damit werden die lokal vorhandenen Artefakte aus dem Repository gelöscht und neu gezogen, falls es hier Probleme gibt, sieht man das sofort ohne sein lokales Maven Repository löschen zu müssen.

Spring, EHCache und Wicket

Hallo zusammen,

ich habe mich kürzlich in einer schlaflosen Nacht mit dem äusserst interessanten Thema „EhCache“ auseinandergesetzt.

Ehcache ist ein transparenter Cache, der ideal mit Spring zusammenarbeitet. Ehcache lässt sich hierbei in verschiedenen Modi betreiben (DiskStore basiert, InMemory etc.).

Um einen QuickWin zu erzielen empfiehlt es sich, hier verschiedene Modi auszuprobieren.

Eine sehr gute und brauchbare Dokumentation dazu findet sich hier.

Da ich persönlich sehr interessiert an Spring und Wicket bin, habe ich natürlich die Möglichkeiten ausgelotet, ehcache hier mit einzubinden.

Offensichtlich gibt es zu der Thematik aber nicht allzu viel Onlinedokumentation, und falls man welche findet ist diese meist veraltet, denn auf dem Sprung zu Spring 3 hat sich hier einiges getan, was die meisten beschriebenen Ansätze nicht mehr verwendbar macht. Ich habe mir als die Mühe gemacht und habe das für mich zum Laufen gebracht, dieser Artikel soll die notwendigen Schritte (nicht zuletzt für mich selbst) dokumentieren.

Zum Thema Wicket und Spring gibt es schon ausreichend gute Onlinedokumentation, beispielsweise hier, hier und hier.

Ich setze also voraus, dass das mehr oder minder funktioniert. Die Frage ist jetzt, was muss getan werden, um das Ganze mit ehcache zum laufen zu bekommen.

Zunächst mal benötigt ehcache eine Konfigurationsdatei, in der die einzelnen Caches konfiguriert werden können, typischerweise wird diese einfach ehcache.xml genannt.


<ehcache>
<defaultCache maxElementsInMemory="500" eternal="true"
overflowToDisk="false" memoryStoreEvictionPolicy="LFU" />

<cache name="shopCache" maxElementsInMemory="5000" eternal="false"
overflowToDisk="false"
diskPersistent="false"
statistics="true"/>
</ehcache>

In dieser Datei haben wir zwei Caches konfiguriert, einen defaultCache der laut ehcache dokumentation immer definiert sein muss und immer dann greift, wenn kein anderer Cache zuständig ist, und viel interessanter, ein „shopCache“, den wir in der Applikation verwenden möchten.

Die Attribute sollten eigentlich selbsterklärend sein, ansonsten gibt die Doku hier wirklich viel her, was evtl interessant ist, ist das Attribut „statistics“, damit stellt ehcache eine Cachestatistik zur Verfügung, die beispielsweise mit einer MBean ausgewertet werden kann, aber dazu später mehr.

Wie bereits erwähnt arbeitet ehcache perfekt mit Spring zusammen, hierzu ist folgende Konfiguration im spring-context notwendig.

Folgende Deklaration von Namespaces kann hilfreich sein:


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<!-- Konfiguration von Beans -->

</beans>


<ehcache:config cache-manager="cacheManager">
<ehcache:evict-expired-elements
interval="60" />
</ehcache:config>

<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:de/pentasys/wicket/ehcache.xml"></property>
</bean>

Zunächst muss die Bean „cacheManager“ vom Typ org.springframework.cache.ehcache.EhCacheManagerFactoryBean definiert werden.

Diese wird anschliessend mit dem element <ehcache:config cache-manager=“cacheManager“> aktiviert.

Und prinzipiell wars das schon mit der Konfiguration!!

Leider war das bisher nur der gemütliche Teil, jetzt gehts darum, die richtigen Dependencies zu deklarieren, damit das Ganze auch baut, und DAS ist wirklich hart, denn die EhCacheManagerFactoryBean wurde beim Umstieg auf Spring 3 umgezogen, und anscheinend nicht richtig dokumentiert.

Folgende Dependencies müssen unbedingt deklariert werden:

Spring Context Support – hier ist die EhCacheManagerFactoryBean verortet und alles was mit ehcache zu tun hat.


<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>

Ehcache-Spring-Annotations – 80% aller online-tutorials verwenden ein modul namens „spring-modules“, diese Modul ist jedoch veraltet, wird nicht mehr gewartet und funktioniert obendrein nicht mit Sping 3. Stattdessen gibt es ein neues Projekt, das noch einfacher in der Handhabung ist und perfekt funktioniert (ich glaube, es ist sogar die einzige aktuell funktionierende Implementierung)


<dependency>
<groupId>com.googlecode.ehcache-spring-annotations</groupId>
<artifactId>ehcache-spring-annotations</artifactId>
<version>1.1.3</version>
</dependency>

Zusätzlich müsst ihr natürlich die entsprechenden Spring Dependencies deklarieren, aber auf diese verzichte ich an dieser Stelle einfach mal.

Damit lässt sich das Projekt schonmal bauen, aber wir haben noch nichts gewonnen, denn wir müssen ehcache noch genau sagen, welcher Methodenaufruf in welcher Bean wohin gecached werden soll, nichts einfacher als das. Hierzu Annotieren wir einfach in einem beliebigen Spring-Service die entsprechenden Methoden wie folgt:


@Cacheable(cacheName = "shopCache")
public List<ProductBundle> products() {
timeOut();
return new ArrayList<ProductBundle>(products.values());
}

Die Annotation @Cacheable kann man Methoden deklarieren, deren Rückgabewert im Cache gespeichert werden sollen, welcher Cache das sein soll gibt man mit dem Attribut „shopCache“ an. Dies ist der Cache, den wir zuvor in der ehcache.xml definiert haben.

Ein weiterer typischer Usecase ist, dass ein Cache beim Aufruf einer bestimmten Methode geleert werden soll. Nichts leichter als das:


@TriggersRemove(cacheName="shopCache",removeAll=true)
public void storeOrder(Order order){
if(order.getBundleList().isEmpty()){
throw new RuntimeException("error, no bundles in order");
}
orders.add(order);
}

Dies veranlasst ehcache, nach dem Aufruf der Methode den Cache zu invalidieren.

Statistiken

Wie können wir jetzt aber auswerten, wie gut oder schlecht unser Caching funktioniert? Dies ist ein idealer Fall für Mbeans! Hierzu kann testweise einfach mal folgendes im Spring-Context deklariert werden:


<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true" />
</bean>

<bean class="net.sf.ehcache.management.ManagementService"class="net.sf.ehcache.management.ManagementService"
init-method="init">
<constructor-arg ref="cacheManager" />
<constructor-arg ref="mbeanServer" />
<constructor-arg value="true" />
<constructor-arg value="true" />
<constructor-arg value="true" />
<constructor-arg value="true" />
</bean>

Dies ist die einfachste Art und Weise, in Spring einen MBean Server zu starten und in diesem eine MBean zu deklarieren, die uns Auskunft über den Zustand des Caches gibt.

Anschliessend kann man sich einfach mal mit JConsole auf den MBeanserver verbinden. Was man dann sieht ist ungefähr folgendes:

Also ich persönlich bin begeistert, wie einfach und transparent das ging, hätte ich vorher eine Beschreibung wie diesen Artikel ( — 🙂 –) gefunden, wäre das Caching eine Sache von 30min gewesen.

Das Ganze ist in einem Demoprojekt verfügbar und kann hier ausgecheckt werden:

git@github.com:dilgerma/Wicket-Workshop-Sources.git

und hier unter advanced-workshop/advanced.

Die einzige Frage die sich mir noch stellt, wie kriege ich den Cache Session-Scoped. SOweit ich das beurteilen kann, ist der Cache, wie er aktuell konfiguriert ist im Applicationscope, das heisst, gilt für alle. Bisher habe ich es nicht hinbekommen, das Ganze für jede Session zu konfigurieren, für alle Tipps bin ich dankbar.

Ansonsten freue ich mich natürlich über Kommentare.

Deployment mit Maven 2, Cargo und Glassfish

Hallo zusammen,

da ich schon lange keine richtig guten Technischen Beiträge hier im Blog verfasst habe, wirds allerhöchste Zeit.

Die regelmäßigen Leser wissen, dass ich ein kleines Spielwiesenprojekt habe, in dem ich immer wieder mal neue Sachen ausprobiere, heute hatte ich ein wenig Zeit, und ich habe mir vorgenommen, das ganze Projekt (ein EAR) mittels Maven und Cargo deploybar zu machen.

Cargo ist eine sehr einfache Java-API mit folgendem Ziel:

Cargo is a thin wrapper that allows you to manipulate Java EE containers in a standard way.

Das schöne ist, dass Cargo auch über ein Maven-Plugin verfügt, und da mein Demo-Projekt zufälligerweise auch auf Maven basiert, kann mit Hilfe des Cargo Plugins problemlos ein Deployment in eine installierte ApplicationServer-Instanz vorgenommen werden.

Um das Ganze in Aktion zu sehen, empfehle ich dringend, das Demoprojekt auszuchecken, und zwar von hier mit Hilfe des Befehls :

git clone git://github.com/dilgerma/wicket-ejb-maven-prototype.git git-project

Um das Projekt starten zu können sollte man sich einen Glassfish-AS V3 lokal installieren. Einzige Anpassung
die notwendig ist, ist der Pfad zum AS, der in der pom des Maven-Artefaktes in base/ear/pom.xml angepasst werden muss.
Die Property heißt: appserv.dir und muss auf das Glassfish-Verzeichnis zeigen (z.B. /opt/glassfishV3).

Das Projekt verwendet die Derby-DB, die mit dem GlassfishV3 zusammen ausgeliefert wird. Diese sollte zuvor gestartet werden,
und zwar im Glassfish-AS/bin Verzeichnis mit dem Befehl:

GLASSFISH_HOME/bin/asadmin start-database

Um das Projekt zu starten sollte einmalig das Projekt durchgebaut werden, und zwar im base-Projekt mit folgendem Befehl:

mvn clean install -Preal

und anschließend im ear Modul:

mvn cargo:start

Dieser Befehl startet sowohl den Application-Server und führt ebenfalls das Deployment des soeben gebauten EAR-Archives
aus. Im folgenden gehe ich noch ein wenig auf die Konfiguration ein, hauptsächlich für mich selbst zur Dokumentation.

Um das EAR-Deployment mit Cargo zu konfigurieren muß zunächst das dazu notwendige Maven-Cargo-Plugin konfiguriert werden, hierzu brauchen wir folgende Repositories, die in der Base-Pom deklariert sind.

<plugin> <groupId>org.codehaus.cargo</groupId> <artifactId>cargo-maven2-plugin</artifactId> <version>1.0.5-SNAPSHOT</version></plugin>

Die restliche Konfiguration erfolgt direkt in der pom.xml des EAR-Projektes.

Was wir hier benötigen ist das cargo-maven2-plugin.

<build> <finalName>hp-app</finalName> <plugins> <plugin> <groupId>org.codehaus.cargo</groupId> <artifactId>cargo-maven2-plugin</artifactId> <version>1.0.5-SNAPSHOT</version> <!-- Configuration Details in http://cargo.codehaus.org/Maven2+Plugin+Reference+Guide#Maven2PluginReferenceGuide-configurationlocatedBlockquote--> <configuration> <container> <containerId>${appserv.cargo.id}</containerId> <home>${appserv.dir}</home> <type>installed</type> </container> <configuration> <type>standalone</type> <properties> <cargo.hostname>localhost</cargo.hostname> </properties> <configfiles> <configfile> <!--file>${appserv.dir}/glassfish/domains/${glassfish.domain}/config/domain.xml</file--> <file>src/main/resources/glassfish-config/domain.xml</file> <todir>cargo-domain/config</todir> </configfile> </configfiles> <deployables> <deployable> <groupId>de.md</groupId> <artifactId>ear</artifactId> <type>ear</type> </deployable> </deployables> </configuration> </configuration> </plugin></plugins>

Betrachten wir die Konfiguration noch ein wenig genauer:

Zunächst deklarieren wir mal die Abhängigkeit auf das cargo2-plugin (hier in der Version 1.0.5-SNAPSHOT).

Das Plugin selbst hat aber wenig Nutzen, es muss konfiguriert werden.
Hierfür gibt es den Configuration-Tag innerhalb jeder Plugin-deklaration.

Was zunächst konfiguriert werden muss ist der Container selbst, dieser Konfigurationsteil konfiguriert quasi
das Cargo-Plugin und den verwendeten AS.

<container> <containerId>${appserv.cargo.id}</containerId><home>${appserv.dir}</home> <type>installed</type> </container>
Eine gute Referenz für die Konfiguration von Cargo findet sich hier.

Über das Attribut containerId wird Cargo mitgeteilt, welcher AS denn tatsächlich im Einsatz ist, dies sind feste Strings und
können hier nachgelesen werden, für den Glassfish V3 lautet der String „glassfishv3“.

Das Attribut home verweist auf das Home-Verzeichnis des Glassfish-Servers.

Wichtig ist auf das Attribut type, dieses Attribut kann die Werte „installed„, „embedded“ und „remote“ annehmen.
Was ist aber der Unterschied? Im Normalfall (und wie ich in diesem Fall) wird das Plugin zur Entwicklungszeit verwendet, und hier
hauptsächlich um ein EAR in einen lokal installierten AS zu deployen. Deswegen wird von uns auch die Variante „installed“ verwendet, was
nichts anderes für Cargo bedeutet, als das der AS lokal bereits installiert ist.

Embedded bedeutet nichts anderes, als das der Container in der gleichen JVM und sogat im gleichen Thread wie Cargo ausgeführt wird. In diesem Fall ist es wichtig, dass die Container-Jars im Classpath verfügbar sind. Der einzige Container der aktuell den Embedded-Mode unterstützt ist der Jetty-Container in der Version 4,5 oder 6.

Damit wäre der Container vollständig konfiguriert. Was jetzt noch passieren muß ist die Konfiguration für das Cargo-Plugin selbst.

Hier verwenden wir folgenden Tag:

<configuration> <type>standalone</type> <properties> <cargo.hostname>localhost</cargo.hostname> </properties> <configfiles> <configfile><!--file&gt;${appserv.dir}/glassfish/domains/${glassfish.domain}/config/domain.xml&lt;/file--><br /> <file>src/main/resources/glassfish-config/domain.xml</file><todir>cargo-domain/config</todir> </configfile> </configfiles> <deployables> <deployable> <groupId>de.md</groupId><artifactId>ear</artifactId> <type>ear</type></deployable></deployables></configuration>

Zunächst ist es wichtig, den Typ der Konfiguration zu definieren. Folgende Werte sind prinzipiell möglich:standalone, existing und runtime.

Standalone-Konfiguration bedeutet, dass Cargo den Container jedesmal von neuem komplett neu aufsetzt.

Existing-Konfiguration bedeutet, dass Cargo eine bestehende Konfiguration wiederverwendet.

Runtime-Konfiguration bedeutet, das die Konfiguration erst zur Laufzeit festgelegt wird.

Im Idealfall verwendet man eine Existing-Konfiguration, da ansonsten alle Datenbank-settings etc. bei jedem Starten des Containers jedesmal neu gesetzt werden müssen. Leider, leider, leider unterstützt GlassfishV3 keine Verwendung von Existing-Konfigurationen. Um das zum Laufen zu bringen habe ich einige Zeit investieren müssen.

Versucht man eine Existing-Konfiguration zu verwenden stößt man auf folgende Fehlermeldung:


org.codehaus.cargo.container.ContainerException: Cannot create configuration. There's no registered configuration for the parameters (container [id = [glassfish3x], type = [installed]], configuration type [existing]). Valid types for this configuration are:
 - standalone

Nicht ganz einfach, daraus schlau zu werden, richtig? Und ständig die Konfigurationen für den AS neu aufzusetzen ist definitiv keine Option. Natürlich gibt es einen kleinen Workaround:).

Wir können einfach ein bestehendes Glassfish-Configuration-File wiederverwenden. Ich habe dieses File mal direkt im EAR-Projekt unter src/main/resources/glassfish-config/domain.xml bereitgestellt.

Eingebunden werden kann das Ganze auf folgende Art und Weise.

<configfiles>
    <configfile>
          <file>src/main/resources/glassfish-config/domain.xml</file>
          <todir>cargo-domain/config</todir>
    </configfile>
</configfiles>

Das Attribut file verweist auf das Konfigurationsfile, in diesem Fall ein Domain-Configuration-File des Glassfish.
Die Domain die Defaultmäßig von Cargo neu erzeugt wird heißt „cargo-domain „, dies läßt sich auch nicht ändern, soweit ich das bisher sehe. Das Konfigurationsfile muß also zur Laufzeit in das Config-Dir der
Cargo-Domain kopiert werden.
Das passiert mit dem Tag „todir„.

Zuletzt muß Cargo noch mitgeteilt werden, was überhaupt deployed werden kann.


<deployables>
 <deployable>
 <groupId>de.md</groupId>
 <artifactId>ear</artifactId>
 <type>ear</type>
 </deployable>
 </deployables>

Das wars, die Applikation fährt jetzt hoch, wird komplett deployed, die Konfiguration des Glassfish wird zur Laufzeit geladen.

Das einzige was ich noch nicht hinbekommen hab, ist das auch automatisch die Datenbank des Glassfish hochgefahren wird. Das muss momentan immer noch manuell passieren.

Ich hoffe, der Artikel machts dem Einen oder Anderen ein wenig einfacher. Über Kommentare freue ich mich natürlich.

Brauchbarer Maven-Archetype für die Google App Engine

Hallo zusammen,

zufällig bin ich heute über einen wirklich brauchbaren Maven-Archetype für die Google App Engine gestossen. Erzeugen lässt sich
ein neues Maven Projekt einfach durch

mvn archetype:generate -DarchetypeGroupId=org.fornax.cartridges  -DarchetypeArtifactId=fornax-cartridges-sculptor-archetype-appengine  -DarchetypeVersion=1.7.0-SNAPSHOT  -DarchetypeRepository=http://www.fornax-platform.org/archiva/repository/snapshots/

Gefunden habe ich das Ganze hier

Vielen Dank dafür!

Maven local Repository

Nur so als Tipp am Rande,

ein lokales Repository konfiguriert man entweder in der ~/.m2/conf/settings.xml oder in der $M2_HOME/conf/settings.xml.

Das GAnze schaut so aus:

<localRepository>G:/development/libs/maven_repo/</localRepository>

und nicht so:

<localRepository>G:/development/libs/maven_repo</localRepository>

Man beachte den / am Ende, der Spass hat mich einen ganzen Abend gekostet um den Build wieder zum Laufen zu kriegen. Zumindest sind jetzt alle Poms wieder aufgeräumt;-)

Dependency auf lokale EJB

Da scheinbar die Standard-Maven-Repositories keine API für EJB3 unterstützen, kann man die lokalen Jars aus seiner Appserverinstallation so verwenden:

<dependencies>
<dependency>
<groupId>glassfish</groupId>
<artifactId>javax.ejb</artifactId>
<version>LATEST</version>
<scope>system</scope>
<systemPath>${glassfish.home}/modules/javax.ejb.jar</systemPath>
</dependency>
<dependency>
<groupId>org.apache.openejb</groupId>
<artifactId>api</artifactId>
<version>3.1.1</version>
<type>pom</type>
<scope>compile</scope>
</dependency>
</dependencies>

Natürlich muss hierfür zusätzlich die Property glassfish.home deklariert werden.

Um EJB3 verwenden zu können, muss dies Maven noch so mitgeteilt werden:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-ejb-plugin</artifactId>
            <configuration>
                <ejbVersion>3.0</ejbVersion>
            </configuration>
        </plugin>
    </plugins>
</build>
Zusätzlich sollten die Compiler Settings auf 1.5 geeicht werden:
<plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-compiler-plugin</artifactId>
 <version>2.0.2</version>
 <configuration>
 <source>1.5</source>
 <target>1.5</target>
 </configuration>
 </plugin>

Um einen Client zu generieren, einfach folgenden Parameter für das Maven EJB Plugin setzen.
 <configuration>
          <!-- this is false by default -->
          <generateClient>true</generateClient>
        </configuration>