Results for category "Eclipse"

40 Articles

JPA/EclipseLink 2 & Spring 3.0.2: The container policy [IndirectListContainerPolicy(class org.eclipse.persistence.indirection.IndirectList)] is not compatible with transparent indirection

Nachdem ich mir die letzten beiden Tage ein paar Sachen zu JPA und JTA durchgelesen hatte, setzte ich eine kleine Test-Anwendung auf, die mir mit Hilfe von Spring 3.0.2 und JPA/EclipseLink 2 Benutzer und deren Gruppen aus einer Datenbank laden sollte.
Das Datenbankschema dazu war einfach: Tabelle user, Tabelle group – zwischen beiden besteht eine n:m-Beziehung (Zwischentabelle user_in_group)

persistence.xml:

<?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="WebDefault" transaction-type="RESOURCE_LOCAL">
 <class>de.ecw.project.sql.vo.UserVO</class>
 <class>de.ecw.project.sql.vo.GroupVO</class>
 <properties>
 <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
 <property name="eclipselink.ddl-generation.output-mode" value="both"/>
 </properties>
 </persistence-unit>
</persistence>

GroupVO.java

package de.ecw.project.sql.vo;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

import de.ecw.project.sql.Schema;

@Entity
@Table(name = Schema.GROUP_TABLE)
public class GroupVO
{
    @Id
    @GeneratedValue
    @Column(name = Schema.COLUMN_ID)
    private long id;

    @Column(name = Schema.COLUMN_NAME)
    private String name;

    public void setId(long id)
    {
        this.id = id;
    }

    public long getId()
    {
        return id;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public String getName()
    {
        return name;
    }
}

UserVO.java

package de.ecw.project.sql.vo;

import java.util.Collection;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;

import org.springmodules.validation.bean.conf.loader.annotation.handler.Length;
import org.springmodules.validation.bean.conf.loader.annotation.handler.NotBlank;

import com.thoughtworks.xstream.annotations.XStreamAlias;

import de.ecw.project.sql.Schema;

@XStreamAlias("user")
@Entity
@Table(name = Schema.USER_TABLE)
public class UserVO
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = Schema.COLUMN_ID)
    private long id;

    @NotBlank
    @Length(max = 255, min = 10)
    @Column(name = Schema.USER_COLUMN_USERNAME)
    private String username;

    @NotBlank
    @Length(max = 255, min = 5)
    @Column(name = Schema.COLUMN_NAME)
    private String name;

    @Column(name = Schema.USER_COLUMN_PASSWORD)
    private String password;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = Schema.USER_IN_GROUP_TABLE, joinColumns = @JoinColumn(name = Schema.COLUMN_USER_ID), inverseJoinColumns = @JoinColumn(name = Schema.COLUMN_GROUP_ID))
    @OrderBy(Schema.COLUMN_ID + " DESC")
    private Collection<GroupVO> groups;

    public void setName(String name)
    {
        this.name = name;
    }

    public String getName()
    {
        return name;
    }

    public void setUsername(String username)
    {
        this.username = username;
    }

    public String getUsername()
    {
        return username;
    }

    public void setId(long id)
    {
        this.id = id;
    }

    public long getId()
    {
        return id;
    }

    public String toString()
    {
        return "user";
    }

    public void setPassword(String password)
    {
        this.password = password;
    }

    public String getPassword()
    {
        return password;
    }

    public void setGroups(Collection<GroupVO> groups)
    {
        this.groups = groups;
    }

    public Collection<GroupVO> getGroups()
    {
        return groups;
    }
}

dispatcher-servlet.xml

...
	<context:component-scan base-package="de.ecw" />

	<bean id="dataSource" name="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.gjt.mm.mysql.Driver" />
		<property name="url" value="jdbc:mysql://localhost:3306/test" />
		<property name="username" value="root" />
		<property name="password" value="" />
	</bean>

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="jpaVendorAdapter">
			<bean
				class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
				<property name="showSql" value="true" />
				<property name="generateDdl" value="true" />
				<property name="databasePlatform"
					value="org.eclipse.persistence.platform.database.MySQLPlatform" />
			</bean>
		</property>
		<property name="loadTimeWeaver">
			<bean
				class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver" />
		</property>
	</bean>

	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<bean id="userDAO" name="userDAO" class="de.ecw.project.sql.dao.impl.UserDAOImpl">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>
...

Wenn ich die Anwendung im Tomcat startete, wurden keine Fehler ausgeworfen – sobald aber das erste Mal auf die DAO-Schicht bzw. VOs zugegriffen wurde, schmiss mir EclipseLink folgenden Fehler:

Local Exception Stack:
Exception [EclipseLink-148] (Eclipse Persistence Services - 2.0.0.v20091127-r5931): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: The container policy [IndirectListContainerPolicy(class org.eclipse.persistence.indirection.IndirectList)] is not compatible with transparent indirection.
Mapping: org.eclipse.persistence.mappings.ManyToManyMapping[groups]
Descriptor: RelationalDescriptor(User --> [DatabaseTable(user)])

Bei Google ließ sich bis auf zwei Einträge dazu nichts finden; die in den Threads beschriebenen Lösungsvorschläge brachten auch nichts.

Wenn ich mir die Dokumentation von Spring komplett durchgelesen hätte , wäre ich auch schneller auf die Lösung gekommen:

  • In der dispatcher-servlet.xml muss SimpleLoadTimeWeaver durch InstrumentationLoadTimeWeaver ersetzt werden
  • Die Eclipse-Anwendung muss mit den VM Argumenten -javaagent:
    <Pfad>/WebContent/WEB-INF/lib/org.springframework.instrument-3.0.2.RELEASE.jar
    gestartet werden.
  • Zusätzlich habe ich noch in der server.xml im Kontext der Anwendung (<Context…) den TomcatInstrumentableClassLoader eingebunden (<<Loader loaderClass=”org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader” useSystemClassLoaderAsParent=”false”/>)

Nach einem Neustart des Tomcats lief dann die Anwendung auch und die zugehörgen Datenbanktabellen wurden automatisch erzeugt.

Google Plugin for Eclipse / GWT 1.6

Google hat nun ein eigenes Plugin für Eclipse veröffentlicht. Von seiner Funktionalität entspricht es dem Googlipse-Plugin. Sollten wir für ein zukünftiges Projekt wieder GWT einsetzen, werde ich das Google Plugin antesten. Ein Key-Feature, was unbedingt für einen Wechsel von Googlipse zu Google Plugin sprechen würde, existiert meiner Meinung nach nicht.

Weiterhin wurde GWT 1.6 veröffentlicht. Durch interne Änderungen in den Verzeichnisstrukturen wird aber auch hier für unser ggw. Projekt vermutlich kein Release-Wechsel stattfinden. Eine kurze Übersicht über die Changes:

  • Änderung der Verzeichniskonventionen
  • Server-Code (RPC-Services) können nun ohne Debugger-Restart geändert werden
  • (Ecl)EMMA läuft nun mit GWT flüssiger
  • Auf Multi-Core-Maschinen wird nun die Kompilierung parallelisiert – für mich wäre das ein Grund, auf GWT 1.6 zu wechseln
  • Event Handling wird nun mit dem Handler-Pattern realisiert
  • DatePicker ist nun als Standard-Widget mit in der Distribution

Mehr zu den gefixten Fehler aus dem Release Candidate gibt es im Bugtracker des GWTs.

Modul Web-Programmierung: 4 / 7 Aufgaben eingeschickt

Die Aufgaben zum Thema CSS, XML/XSLT, Javascript und PHP habe ich heute eingeschickt. CSS war etwas frickelig, da die Beschreibung der Aufgabe IMHO etwas doppeldeutig geschrieben ist. Mal sehen, was dabei herauskommt.

Für die Bearbeitung der XML/XSLT-Aufgabe kann ich übrigens jedem empfehlen, Eclipse Ganymede mit WST und dem XSLT-Plugin XSLT Tooling zu installieren.

Morgen geht es dann mit JSP, ASP.NET und AJAX weiter. Die Tests habe ich noch nicht bearbeitet, ASP.NET ist für mich (widerliches) Neuland – aber ich stehe etwas unter Zeitdruck, da ich bis zum 16.3. die Vorleistungen erbracht haben muss.

TextUML – freies Eclipse Plugin zum Erstellen von UML-Diagrammen

TextUML ist ein freies Eclipse Plugin-In mit dem sich UML-Diagramme erstellen lassen. Im Gegensatz zu anderen Plugins wird bei TextUML “programmiert”, d.h. das Schema wird heruntergetippert. Als Programmierer ist das natürlich vorteilhaft, da ich mit der Tastatur meistens schneller unterwegs bin als mit der Maus.
Sobald ich beim Studium den UML-Part beginne, werde ich von dem Tool sicherlich gebrauch machen.

Akzeptanztests für das GWT mit Hilfe von Selenium

Selenium ist ein Sammlung von Tools, mit deren Hilfe sich Akzeptanztests definieren lassen. Selenium IDE kann zum automatischen Aufzeichnen von Aktionen benutzt werden. Dabei wird SI als Plugin im Browser installiert.
So weit, so gut – ich wollte nun für unsere GWT-Applikation Selenium einsetzen, da das manuelle Testen einiges an Zeit in Anspruch nimmt.
Das Warten auf die Antwort der AJAX-Aufrufe löste ich pragmatisch durch pause(). Die User-Extension waitForCondition ignorierte ich für AJAX-Aufrufe erst einmal.

Für mich enstand nun folgendes Problem: die einzelnen Elemente der TreeView (com.google.gwt.user.client.ui.Tree) ließen sich nicht anklicken.

  • SI zeichnete die Clicks nicht auf. Der Grund dafür liegt darin, dass das onClick-Event nicht auf Layer oder Labels an den Browser gefeuert wird.
  • Über die ID (gwt-uid-…) konnte ich den Click (click -> id=gwt-uid-…) laut IDE zwar durchführen, im Browser passierte aber nichts.
  • Eine manuelle Festlegung der ID im GWT (treeItem.ensureDebugId(“element”)) führte zum selben Ergebnis: im Browser passierte rein gar nichts.

Als Fazit kann ich leider nur sagen, dass die Idee hinter Selenium zwar richtig gut ist. Allerdings funktioniert das Zusammenspiel zwischen GWT und Selenium für unsere Zwecke überhaupt nicht. Dementsprechend: Back to the roots und von Hand testen 🙁

Bei meiner Recherche nach möglichen Workarounds bin ich übrigens über CubicTest gestoßen. CubicTest ist ein Eclipse-Plugin mit denen sich Testfälle in der Eclipse-IDE visuell modellieren lassen. Die Tests könne danach unter anderem als Selenium-Tests exportiert werden.

Tool zum Resizen von Fenstern über mehrere Bildschirme

Eclipse-Entwickler kennen das: Sie besitzen zum Entwickeln zwar zwei Bildschirme, aber Eclipse unterstützt kein Multi-Display-Support bzw. keinen, der wirklich zuverlässig funktioniert.
Auf Codeplex wurde nun das Tool VirtualScreenMax releast, dass eine Anwendung auf mehrere Bildschirme resizt. Ich finde das Tool mehr als praktisch, denn nun habe ich Eclipse im Vollbild-Modus auf beiden Bildschirmen laufen und muss nicht mehr Detached-Outlines u.ä. benutzen.

JDBC-Datenbankverbindung in BIRT-Reports injizieren

Szenario: Ich möchte aus Java heraus einen IRunAndRenderTask für BIRT anstoßen. Der zu erstellende Report soll die Datenbankverbindung per Property übergeben bekommen.

Lösungsansätze:
1. Benutzen eines erweiterten ODA-Treibers (mit Connection Pooling: http://birtworld.blogspot.com/2007/01/birt-connection-pooling-continued.html)
2. Zugriff auf die Datenbank-Verbindung über JNDI
3. Benutzung von IConnectionFactory.PASS_IN_CONNECTION.

Letztere Methode erlaubt das injizieren einer vorhandenen Datenbankverbindung in den Report. Allerdings ist in dem ODA-Treiber bis 2008-11-17 (also vorletzte Woche) noch ein Bug vorhanden, der die Datenbankverbindung mit erfolgreichem Erstellen des Reports wieder schließt. Der Bug wurde aber gefixt, so dass sich mit dem Identifier IConnectionFactory.CLOSE_PASS_IN_CONNECTION das Schließen der Verbindung deaktivieren lässt.

Was für ein Frickel-Krams – noch kurz ein paar Stichworte: JDBC, DataSource, dynamic, BIRT, inject, user property, connection, pooling