Category Archives: maven

Hibernate – Collection-Size mit Lazy-Initialization

Es gibt einige klassische Probleme, die man mit JPA ständig zu lösen hat, für die aber scheinbar kaum jemand eine Sofort-Lösung parat hat.

Ein Klassiker dieser Gattung ist die Größe einer Collection zu erfragen, ohne diese vollständig zu initialisieren.

Nehmen wir das Standardbeispiel eines Blogs.

Ein Blog besteht aus Einträgen und Kommentaren. Die Entity für einen Blogeintrag kann beispielsweise so aussehen:

[code lang=”java” inline=”yes”]
@Entity
@Table(name=”POST”)
public class Post {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name=”POST_ID”)
    Integer postId;

    @Column(name=”TITLE”)
    String title;

    @Column(name=”POST_DATE”)
    Date postDate;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name=”POST_ID”,referencedColumnName = “POST_ID”)
    private List<Comment> comments = new ArrayList<Comment>();

    public Integer getPostId() {
        return postId;
    }

    public void setPostId(Integer postId) {
        this.postId = postId;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Date getPostDate() {
        return postDate;
    }

    public List<Comment> getComments(){
        return comments;
    }

    public void addComment(Comment comment){
        this.comments.add(comment);
    }

    @PrePersist
    public void setPostDate() {
        this.postDate = new Date();
    }

}
[/code]

Das Setup ist ein Standard-Hibernate/Spring/JPA Setup. Beispielsweise können wir mit Spring-Data für Posts folgendes Repository definieren, um auf die Einträge zuzugreifen.

[code lang=”java” inline=”yes”]

public interface PostRepository extends JpaRepository<Post, Integer> { }

[/code]

Um das Ganze zu testen definieren wir folgenden Test-Case

[code lang=”java” inline=”yes”]

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:META-INF/test-context.xml")
public class PostRepositoryTest {

    @Autowired
    PostRepository repository;

    @Test
    public void test() {
        Post post = new Post();
        Comment firstComment = new Comment("Kommentar Text1","Martin");
        post.addComment(firstComment);
        Comment secondComment = new Comment("Kommentar Text1","Martin");
        post.addComment(secondComment);
        post.setTitle("First Post");

        repository.save(post);

        Post dbpost = repository.findOne(post.getPostId());
        assertNotNull(dbpost);
        System.out.println(dbpost.getTitle());
    }

}

[/code]

Das generierte DDL-SQL von Hibernate sieht so aus

Hibernate: create table POST (POST_ID integer generated by default as identity, POST_DATE timestamp, TITLE varchar(255), primary key (POST_ID))
Hibernate: create table comments (id bigint generated by default as identity, author varchar(255), comment varchar(255), POST_ID integer, primary key (id))
Hibernate: alter table comments add constraint FKDC17DDF4D3BC1BD8 foreign key (POST_ID) references POST

Für die Inserts generiert Hibernate folgende Queries

Hibernate: insert into POST (POST_ID, POST_DATE, TITLE) values (null, ?, ?)
Hibernate: insert into comments (id, author, comment) values (null, ?, ?)
Hibernate: insert into comments (id, author, comment) values (null, ?, ?)
Hibernate: update comments set POST_ID=? where id=?
Hibernate: update comments set POST_ID=? where id=?

Soweit alles Standard. Jetzt wird es interessant. Wir möchten die Anzahl an Kommentaren ermitteln. Kein Problem oder?

Zunächst definieren wir eine neue Methode getCommentsCount() in der Post-Entity

 public Integer getCommentsCount(){
        return comments.size();
 }

Den Test ergänzen wir um einen einfachen Assert.

assertEquals(new Integer(2), post.getCommentsCount());

Das funktioniert nicht, aber nur deswegen, weil Hibernate die Collection nicht direkt beim Laden initialisiert (Lazy-Initialization). Das bedeutet, Kommentare werden nur geladen, wenn auch wirklich auf sie zugegriffen wird. Das Nachladen einer Lazy-Initialisierten Collection funktioniert aber leider nur im Kontext einer Transaktion und nicht mit einer Entity die bereits detached ist.
Der Test spiegelt das auch sofort wieder.

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: de.effectivetrainings.entities.Post.comments, could not initialize proxy - no Session

Welche Möglichkeiten haben wir jetzt?

Eager Initialization

Wir können Hibernate anweisen, die Collection Eager zu initialisieren, das bedeutet, immer wenn eine Post-Entity geladen wird, wird Hibernate auch gleich alle Kommentare laden.

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name="POST_ID",referencedColumnName = "POST_ID")
private List&lt;Comment&gt; comments = new ArrayList&lt;Comment&gt;();

Hibernate generiert uns folgendes SQL.

Hibernate: select post0_.POST_ID as POST1_0_0_, post0_.POST_DATE as POST2_0_0_, post0_.TITLE as TITLE0_0_ from POST post0_ where post0_.POST_ID=?
Hibernate: select comments0_.POST_ID as POST4_0_1_, comments0_.id as id1_1_, comments0_.id as id1_0_, comments0_.author as author1_0_, comments0_.comment as comment1_0_ from comments comments0_ where comments0_.POST_ID=?

Aus Performance-Gründen kann das nicht erwünscht sein, beispielsweise wenn wir nur eine Liste von Posts anzeigen möchten aber an den Kommentaren zunächst gar nicht interessiert sind. Jetzt haben wir ein Dilemma, aus dem es scheinbar keinen Ausweg gibt, oder? Dachte ich auch, bis ich auf ein spezielles Feature von Hibernate gestossen bin.

Extra-Lazy Initialization

Hibernate bietet ein sehr nettes Feature das sich Extra-Lazy Initialization nennt. Hier initialisiert Hibernate eine Collection teilweise, aber nur die Elemente, die tatsächlich gebraucht werden, was sogar einzelne Elemente in der Liste sein können.

Probieren wir es aus.

Wir ändern hierfür das Collection-Mapping für die Kommentare folgendermaßen.

 @OneToMany(cascade = CascadeType.ALL)
 @JoinColumn(name="POST_ID",referencedColumnName = "POST_ID")
 @LazyCollection(LazyCollectionOption.EXTRA)
 private List&lt;Comment&gt; comments = new ArrayList&lt;Comment&gt;();

Das allein macht unseren Test nicht grün. Zusätzlich fügen wir folgende private Methode in die Post-Klasse ein.

 @PostLoad
 private void initCommentCount(){
        comments.size();
 }

Jedesmal wenn ein Post geladen wird, fragen wir die Größe der Kommentar-Collection ab. Das SQL das jetzt von Hibernate generiert wird ist folgendes:

Hibernate: select post0_.POST_ID as POST1_1_0_, post0_.POST_DATE as POST2_1_0_, post0_.TITLE as TITLE1_0_ from POST post0_ where post0_.POST_ID=?
Hibernate: select count(id) from comments where POST_ID =?

Hibernate ist wirklich unglaublich klug und erkennt, dass nicht die Collection selbst sondern die die Größe benötigt wird. Deswegen wird auch kein Select auf alle Kommentare sondern nur ein select(count) ausgeführt, was aus Performance-Sicht optimal ist.Das lässt sich auch beweisen, in dem wir einfach mal auf ein Element in der Collection zugreifen.

 dbpost.getComments().get(0);

verursacht nach wie vor unsere

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: de.effectivetrainings.entities.Post.comments, could not initialize proxy - no Session

Fazit

Das ist ein sehr oft diskutiertes Problem, ich finde diese Lösung ziemlich elegant und beeindruckend. Ich hoffe, der/die Eine oder Andere kann damit was anfangen.

Der Code zu diesem Beispiel findet sich übrigens auf GitHub.

 

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”.

[code language=”xml”]
<?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>

[/code]

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).

[code language=”xml”]

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

[/code]

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:

[code]

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

[/code]

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.

[code language=”xml”]

<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>

[/code]

Das muss abgeändert werden in:

[code language=”xml”]

<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>

[/code]

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.

[code language=”xml”]

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

[/code]

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

[code language=”xml”]
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-context.xml</param-value>
</context-param>
[/code]

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

[code language=”xml”]

<?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>

[/code]

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

Zuletzt definieren wir unsere Wicket-Applikation als SpringBean.

[code language=”java”]

@Component
public class EffectiveApplication extends WebApplication
{

}

[/code]

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.

[code language=”java”]

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

[/code]

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.

[code language=”xml”]

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

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

[/code]

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:

[code language=”xml”]

<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>

[/code]
[code language=”xml”]

<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>

[/code]

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.

[code language=”xml”]

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

[/code]

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)

[code language=”xml”]

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

[/code]

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:

[code language=”java”]

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

[/code]

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:

[code language=”java”]

@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);
}

[/code]

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:

[code language=”xml”]

<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>

[/code]

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 :

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

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:

[code]GLASSFISH_HOME/bin/asadmin start-database[/code]

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

[code]mvn clean install -Preal[/code]

und anschließend im ear Modul:

[code language=”xml”]
mvn cargo:start
[/code]

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.

[code language=”xml”]<plugin> <groupId>org.codehaus.cargo</groupId> <artifactId>cargo-maven2-plugin</artifactId> <version>1.0.5-SNAPSHOT</version></plugin>[/code]

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

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

[code language=”xml”]<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>[/code]

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.

[code language=”xml”]<container> <containerId>${appserv.cargo.id}</containerId><home>${appserv.dir}</home> <type>installed</type> </container>[/code]

Eine gute Referenz für die Konfiguration von Cargo findet sich <a href="http://cargo.codehaus.org/Maven2+Plugin+Reference+Guide#Maven2PluginReferenceGuide-configurationlocatedBlockquote">hier</a>.

Ü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:

[code language=”xml”]<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>[/code]

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:

[code]

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

[/code]

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.

[code language=”xml”]
<configfiles>
<configfile>
<file>src/main/resources/glassfish-config/domain.xml</file>
<todir>cargo-domain/config</todir>
</configfile>
</configfiles>

[/code]

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.

[code language=”xml”]

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

[/code]

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

[code language=”xml”]
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/
[/code]

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:

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

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

Erstellung eines Maven-Projektes unter Eclipse mit WTP

Ich spiele momentan ein wenig mit Maven herum,

eine sehr einfache Möglichkeit, ein Webprojekt mit Maven zu erstellen ist die Verwendung des M2-Eclipse-Plugins.

Hierbei wird einfach das Plugin am einfachsten nur zur Erzeugung eines initialen Maven-Projektes erzeugt.

Ich arbeite lieber mit Externen Targets, um die Maven-Befehle direkt auszuführen, anstatt mich auf die Implementierung eines Maven-Plugins zu verlassen. Hier befindet sich ein Eclipse-Projekt, welches die wichtigsten Targets als Run-Configs definiert und direkt als Projekt importiert werden kann, das Projekt wurde mir von einem lieben Kollegen zur Verfügung gestellt. Importiert man die Run-Configs, hat man unter Extrernal Targets die im unteren Screenshot angezeigten Möglichkeiten.

externaltools

Hat man jetzt ein Maven-Projekt erstellt

newproj

Kann dies über die Verwendung des unten markierten Targets in ein Dynamic Web Projekt verwandelt werden.

target

Vorteil hiervon ist, dass die Eclipse-spezifischen Informationen direkt aus dem Maven-POM generiert werden, es werden also bei Verwendung eines Versions-Kontroll-Systems nur die Maven-Spezifischen Dateien eingecheckt, alles andere wie die .project-Datei oder die .classpath wird erst bei Ausführung des Maven Befehls :

mvn -U -Dwtpversion=${string_prompt:zu verwendende wtp-facet-version}  eclipse:eclipse

erzeugt, nichts anderes macht das ExternalTarget.

Command Framework

Dies ist eigentlich ein älterer Blogeintrag, aber aufgrund eines Fehlers veröffentliche ich diesen hier eben nochnals.

<span style="font-size:11pt;font-family:&quot;">An einem Beispiel will ich hier mal schnell das Platform Command Framework erläutern. Dies soll als einfacher Einstieg dienen, als auch damit ich mir das komplette Thema einmal vor Augen führen kann, da ich momentan in einem relativ grossen Projekt arbeite, wo genau dieses Framework eingesetzt werden<span>  </span>soll.</span>
<span style="font-size:11pt;font-family:&quot;"> </span>
<span style="font-size:11pt;font-family:&quot;">Zuerst sollen an dieser Stelle einige Begriffsdefinitionen gegeben werden.</span>
<span style="font-size:11pt;font-family:&quot;"> </span>
<span style="font-size:11pt;font-family:&quot;">Command : Ein Command kann als eine abstrakte Beschreibung einer Benutzeraktion betrachtet werden. Die Benutzeraktion ist hierbei nicht mit einem Verhalten assoziiert, sondern hier geht es lediglich um die Definition eines Aktion.</span>
<span style="font-size:11pt;font-family:&quot;"> </span>
<span style="font-size:11pt;font-family:&quot;">Handler: Ein Handler ist die Implementierung des Verhaltens einer Command. Die Verknüpfung zwischen Handler und Command erfolgt hierbei über die Command-ID. In einem vorherigen Beitrag habe ichbereits auf einen interessanten IBM-Artikel zu diesem Thema verwiesen, hier können die einzlnen Begrifflichkeiten nochmals genau nachgelesen werden. Weiterhin ist im Eclipse-Magazin in der Ausgabe 02/08 ein durchaus interessanter Artikel zum Thema COmmands, der sich hauptsächlich damit beschäftigt, wie Menu-Strukturen mit Hilfe des Command-Frameworks realisiert werden können.</span>
<span style="font-size:11pt;font-family:&quot;"> </span>
<span style="font-size:11pt;font-family:&quot;">Einem Command können beliebig viele Handler zugewiesen werden, beispielsweise kann ein Command in einem bestimmten View ein komplett anderes Verhalten zugewiesen werden, als beispielsweise innerhalb der MenuBar. Ein ganz gutes Beispiel , welches hier eigentlich immer verwendet wird, ist das COPY-Command. Der Copy-Befehl hat in der MenuBar eine möglicherweise komplett andere Bedeutung als in einem TextViewer, wo beispielsweise Textpassagen kopiert werden sollen. Dies kann über 2 verschiedene Handler für ein Command realisiert werdne. Wichtig zu Beachten ist, dass zwar beliebig viele Handler einem Command zugewiesen werden können, es kann jedoch immer nur ein einziger Handler aktiv geschalten sein.</span>
<span style="font-size:11pt;font-family:&quot;"> </span>
<span style="font-size:11pt;font-family:&quot;">Was ich in diesem Artikel beschreiben möchte, ist wie man jetzt Commands richtig einsetzen kann, und ein wenig auf die Möglichkeiten des Command-Frameworks.</span>
<span style="font-size:11pt;font-family:&quot;"> </span>
<span style="font-size:11pt;font-family:&quot;">Um mit dem Command-Framework richtig arbeiten zu können,muss zusätzlich ein Blick auf die Core-Expression-Language von Eclipse geworfen werden, mit dieser lässt sich nämlich beschreiben, wann ein bestimmer Handler aktiv geschalten werden muss.</span>
<span style="font-size:11pt;font-family:&quot;"> </span>
<span style="font-size:11pt;font-family:&quot;">Um eine Expression zu definieren, definiert man eine Extension für den Extension-Point „</span>org.eclipse.core.expressions.definitions“.
Das könnte beispielsweise so aussehen:

<extension

point=”org.eclipse.core.expressions.definitions”>

<definition

id=”myextensiondefinition”>

<with

variable=”activePartId”>

<equals

value=”myviewID”>

</equals>

</with>

</definition>

<span>   </span>&lt;/extension&gt;

Diese Expression ist aktiv, wenn die variabel „activaPartId“ den Wert „myViewID“ annimmt. Dies kann beispielsweise benutzt werden, um eine Command im Menü freizuschalten, sobald ein bestimmter View geladen wird.

Die wichtigsten bereits definierten Expressions sind im Interface „ISources“ definiert, unter der URL <a href="http://wiki.eclipse.org/Command_Core_Expressions">http://wiki.eclipse.org/Command_Core_Expressions</a> als auch im folgenden kurz erläutert.
<!--[if !supportLists]--><span style="font-family:Symbol;"><span>·<span style="font-family:&quot;font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">         </span></span></span><!--[endif]-->activeContexts (liefert eine COllection der aktuell registrierten Kontexte)
<!--[if !supportLists]--><span style="font-family:Symbol;"><span>·<span style="font-family:&quot;font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">         </span></span></span><!--[endif]-->activeShell (liefert die aktuelle Shell als Shell-Object)
<!--[if !supportLists]--><span style="font-family:Symbol;"><span>·<span style="font-family:&quot;font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">         </span></span></span><!--[endif]-->activeWorkbenchWindow (liefert das aktuelle WorkbenchWindow)
<!--[if !supportLists]--><span style="font-family:Symbol;"><span>·<span style="font-family:&quot;font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">         </span></span></span><!--[endif]-->activeEditor bzw activeEditorId (liefert den aktuellen Editor oder die aktuelle EditorID)
<!--[if !supportLists]--><span style="font-family:Symbol;" lang="EN-US"><span>·<span style="font-family:&quot;font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">         </span></span></span><!--[endif]--><span lang="EN-US">activePart bzw activePartId (s.o)</span>
<!--[if !supportLists]--><span style="font-family:Symbol;"><span>·<span style="font-family:&quot;font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">         </span></span></span><!--[endif]-->selection (liefert die aktuelle WorkbenchSelection)

Im folgenden sind einige Beispiele vorgestellt, die Expressions beschreiben, die folgende Expression evaluiert zu true sobald eine Properties-Datei in der Workbench selektiert wird.

<span lang="EN-US">&lt;activeWhen&gt;</span>
<span lang="EN-US"><span>   </span>&lt;iterate&gt;</span>
<span lang="EN-US"><span>      </span>&lt;adapt type="org.eclipse.core.resources.IResource"&gt;</span>
<span lang="EN-US"><span>         </span>&lt;test property="org.eclipse.core.resources.name" </span>
<span lang="EN-US"><span>               </span>value="*.properties"/&gt;</span>
<span lang="EN-US"><span>      </span>&lt;/adapt&gt;</span>
<span lang="EN-US"> <span>  </span>&lt;/iterate&gt;</span>
<span lang="EN-US">&lt;/activeWhen&gt;</span>
Diese Expression liefert true, sobald ein bestimmter EditorPart aktiviert wird.
<span lang="EN-US">&lt;activeWhen&gt;</span>
<span lang="EN-US"><span>   </span>&lt;with variable="activeEditorId"&gt;</span>
<span lang="EN-US"><span>      </span>&lt;equals value="myEditorId"/&gt;</span>
<span lang="EN-US"><span>   </span></span>&lt;/with&gt;
&lt;/activeWhen&gt;
Um eine innerhalb des Extension-Points für Expression-Definitions definierten Expression zu evaluieren, kann folgendes Fragment genuzt werden:
<span lang="EN-US">&lt;activeWhen&gt;</span>
<span lang="EN-US"><span>   </span>&lt;reference definitionId="meine_definition_id"/&gt;</span>
&lt;/activeWhen&gt;

Um jetzt eine Command zu erstellen, muss man prinzipiell 3 Schritte durchführen (oder mehr, je nach durchzuführender Aktion).
<!--[if !supportLists]--><span><span>1.<span style="font-family:&quot;font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">  </span></span></span><!--[endif]-->Defintion eines Commands
<!--[if !supportLists]--><span><span>2.<span style="font-family:&quot;font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">  </span></span></span><!--[endif]-->Definition eines Handlers (oder 1..n Handlern)
<!--[if !supportLists]--><span><span>3.<span style="font-family:&quot;font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">  </span></span></span><!--[endif]-->Definition der entsprechenden Expression, die den Handler kontextabhängig aktiviert oder deaktiviert.
Sind diese Schritte durchgeführt, hat man schon ein ganz gut laufendes Beispiel. Das wollen wir doch gleich mal probieren.
<!--[if !supportLists]-->

<extension

point=”org.eclipse.ui.handlers”>

<handler

class=“MyHandler”

commandId=“mycommand”>

<activeWhen>

<with

variable=”activePartId”>

<equals

value=“myview”>

</equals>

</with>

</activeWhen>

</handler>

<span>   </span>&lt;/extension&gt;
Man sieht, der Handler wird über das Attribut „commandId“ an ein bestimmtes Command gehängt.
Die aktiv-schaltung per expression sollte an dieser Stelle bereits klar sein.

Um jetzt die Aktivierung bzw. Inaktivierung des Commands zu sehen, definieren wir 2 Views. Einen mit der ID „myview“, innerhalb dessen das Command aktiv sein sollte, und einen mit der ID „myOtherView“, in dem das Command nicht aktiv sein dürfte.

Um dies jetzt schön betrachten zu können, benutzen wird das Command , um einen Menüpunkt in der Anwendung zu erstellen.
Hierfür verwenden wir den Extension-Point „<span style="color:green;">org.eclipse.ui.menus“.</span>
<span style="font-size:11pt;font-family:&quot;">Für diesen definieren wir eine MenuCOntribution. Das sieht prinzipiell so aus:</span>

<extension

point=“org.eclipse.ui.menus”>

<menuContribution

locationURI=“toolbar:myview”>

<command

commandId=“mycommand”

id=“menueconttribution”

label=“Das ist mein Label”

tooltip=“Das ist mein Tooltop”>

</command>

</menuContribution>

<span style="color:black;"><span> </span><span>  </span></span>&lt;/extension&gt;
Dieses Menü-Thema ist sehr schön im aktuellen Eclipse-Magazin beschrieben, weswegen ich an dieser Stelle nicht weiter darauf eingehen werden, was an dieser Stelle jedoch noch interessant ist, sind die Expressions, mit denen eine Command in verschiedenen Menü- , Toolbars etc.. gesetzt werden können, da diese Frage prinzipiell immer wieder auftaucht.
Es gibt prinzipiell die Möglichkeit, Commands in die Top-Level-Menubar, View-Toolbar, Top-Level-Toolbar o.ä.

Um eine Command in einer Menübar zu platzieren kann folgender String für die locationURI angegeben werden:
„menu:&lt;&lt;ID eines Elements&gt;&gt;“ oder „menu:org.eclipse.ui.main.menu“ für das TopLevel Menu.
Um die Command hingegen in die Toolbar zu platzieren, kann der String
„toolbar:&lt;&lt;ID eines Elements&gt;&gt;“ oder „toolbar:org.eclipse.ui.main.toolbar“ für die Top-Level-Toolbar.

In der Toolbar ist jedoch keine Standardgruppe definiert, das bedeutet, dass, bevor mit dieser MenuContribution gearbeitet werden kann, noch eine Gruppe definiert werden muss. Dies geschieht normalerweise im ApplicationActionBarAdvisor, indem man die Methode „fillCoolbar(…)“ überschreibt. Ein CodeSnippet hierfür ist

<span lang="EN-US">ToolbarManager manager = new ToolbarManager();
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
coolBar.add(manager);</span>
<span lang="EN-US"> </span>
Um eine Command in einem Popup zu definieren, kann folgender String verwendet werden:
„popup: &lt;&lt;ID eines validen Kontextes&gt;&gt;“ oder aber „popup:<span> org.eclipse.ui.popup.any“, dieser sollte allerdings, wenn überhaupt, sehr sparsam verwendet werden.</span>
<span>Weiterhin ist <a href="http://wiki.eclipse.org/Menu_Contributions#Declarative_menus_-_some_constraints">http://wiki.eclipse.org/Menu_Contributions#Declarative_menus_-_some_constraints</a> ein relativ guter Link hierzu.</span>
<span> </span>
<span style="font-size:11pt;font-family:&quot;">Einen grossen Nachteil, der bisher in Menüstrukturen bestand, ist das nicht ohne weiteres kontrolliert werden konnte, an welcher Stelle eine bestimmte MenuContribution platziert wird. Dies ist mit diesem Mechanismus ohne weiteres möglich, da hier mit Paramtern die genaue Position festgelegt werden kann. Auf die genaue Funktionsweise des Menümechanismus kann hier nicht weiter eingegangen werden, aber die Platzierung sieht prinzipiell so aus:</span>
<span style="font-size:11pt;font-family:&quot;">“</span>toolbar:org.eclipse.ui.main.toolbar?after=myGroupID<span style="font-size:11pt;font-family:&quot;">”, wobei die ID hinter After eine bestimmte Gruppe oder einen Separator bezeichnet.</span>
<span style="font-size:11pt;font-family:&quot;"> </span>
<span style="font-size:11pt;font-family:&quot;">Schaltet man nun zwischen 2 unterschiedlichen ViewParts hin und her, sieht man , dass die Command je nach aktivierte ViewPart aktiviert bzw. deaktiviert wird. </span>