Advanced   Java   Services Entity Beans 3.0 Back Next Up Home


Einführung


Eine Entity Bean ist mit der Version 3.0 nicht nur ein POJO (plein old java object) geworden sondern kann auch völlig unabhängig von einem BeanContainer (Glassfish, JBoss etc.) agieren. Deshalb spricht man nun auch manchmal nur von Entities statt von Entity Beans. Geblieben ist, daß ein Objekt einer Entityklasse einer Zeile einer Zeile einer Tabelle einer relationalen Datenbank entspricht. Zwei wichtige Hilfsklassen bzw. Interfaces und eine xml-Datei regeln den Zugriff auf die gewählte Datenbank. Dies entspricht der früheren CMP (container managed persistence). Eine BMP (bean maanged persistence) exisiert in diesem Sinne nicht mehr. Der Verbindungsaufbau und die gesamte Datenmanipulation (Persistenz) werden von einer Hilfsklasse erledigt die das Interface javax.persistence.EntityManager implementiert hat. Ein Objekt vom Typ EntityManager erhält man über eine EntityManagerFactory. Eine Implementierung des Interfaces javax.persistence.EntityManagerFactory muß u.a. die Methode createEntityManager() bereitstellen, die das vollbringt was ihr Name erwarten läßt. Die Factory selbst wiederum erhält man über eine weitere Hilfsklasse, die Klasse javax.persistence.Persistence Diese Klasse stellt u.a. die statische Methode createEntityManagerFactory(java.lang.String persistenceUnitName) bereit, mit der man eine Factory erzeugen kann.

Wo findet man die Interfaces und die Implementierungen


Die Interfaces javax.persistence.EntityManager und javax.persistence.EntityManagerFactory sowie die Klasse javax.persistence.Persistence liegen im Archiv javaee.jar, das nach der Installation von Glassfish im Installationsverzeichnis zu finden ist. Die Implementierungen der Interfaces heißen oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerFactoryImpl und oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerImpl und befinden sich im Archiv toplink-essentials.jar. Auch dieses Archiv findet man im Glassfishverzeichnis. Dieses Archiv wird dort ergänzt durch toplink-essentials-agent.jar in dem sich weitere notwendige Hilfsklassen befinden.

Links zu den Archiven


Das Archiv javaee.jar gibt es auch hier.
Die toplink-essentials.jar gibt es auch hier.

Die Beispiele


Es folgen vier Beispiele, die das Grundsätzliche abdecken sollen. Mit dieser Grundlage können dann auch kompexere Beispiele realisiert werden.

Wir werden alle Beispiele ohne Netbeans und ohne Eclipse entwickeln. Stattdessen arbeiten wir mit einem einfachen Editor, etwa mit Textpad. So wird das Zusammenspiel der einzelnen Komponenten am deutlichsten. Der Übergang zu Eclipse sollte dann kein Problem darstellen. Des weiteren verzichten wir der Einfachheit halber darauf die Javaklassen bzw. Interfaces in Packages zu legen. Als Übung können Sie das Beispiel so abändern, daß Sie Packages einsetzen. In der Praxis werden die Klassen immer in Packages gelegt.

1) Entity wird auf lokale Datenbanktabelle abgebildet (MySQL)


Unser erstes Beispiel besteht im wesentlichen aus vier Dateien, einer Entityklasse (Movie), einem EntityHandler (MovieHandler), der Hauptklasse ConnectToMovieDB, die in main() den EntityManager bereitstellt und einer (notwendigen) xml-Datei mit dem Namen persistence.xml, in der der Datenbankzugriff konfiguriert wird. Diese Datei muß in einem eigenen Verzeichnis mit dem Namen META-INF untergebracht sein. Dieses Verzeichnis enthält noch die immer notwendige aber simple Datei MANIFEST.MF. Damit ergibt sich die folgende Struktur

beispiel-1 <dir>
   |
   --- Movie.class  <file>
   --- MovieHandler.class <file>
   --- ConnectToMovieDB.class <file>
   --- META-INF <dir>
         |
         --- MANIFEST.MF <file>
         --- persistence.xml <file>


Die Entity Movie


/*
 entity class

 @Entity (necessary)
 declares the class as an entity bean (i.e. a persistent POJO class),
 this class needs to be mapped to a relational database table.

 @Id (necessary)
 declares the identifier property of this entity bean.

 @GeneratedValue
 indicates that the server automatically generates the primary key value.

@Table (optional)
defines the table name. Each instance of the entity bean represents a row of data in the table.
is set at the class level; it allows you to define the table, catalog, and
schema names for your entity bean mapping.
If no @Table is defined the default values are used, that is the unqualified class name of the entity.

@SequenceGenerator(name = "movie-sequence", sequenceName = "movie-id") (optional)
The @SequenceGenerator defines a sequence generator. A sequence is a database feature.
It returns the next Integer or Long value each time it is called.
*/

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

@Entity
@Table(name="moviedatabase")
public class Movie
{
   @Id
   @GeneratedValue
   private int id;
   private String director;
   private String title;
   private int year;

   public Movie()
   {
      id = year = 0;
      director = title = "";
   }


   public Movie(String director, String title, int year)
   {
     this.director = director;
     this.title = title;
     this.year = year;
   }


   public int getId()
   {
      return id;
   }

   //@Column(name="director")
   public String getDirector()
   {
     return director;
   }

   public void setDirector(String director)
   {
     this.director = director;
   }

   public String getTitle()
   {
     return title;
   }

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

   public int getYear()
   {
     return year;
   }

   public void setYear(int year)
   {
     this.year = year;
   }
}

Der EntityManager erstellt aus dieser Klasse eine Tabelle mit dem Namen "moviedatabase" mit den Spalten ID (INTEGER), DIRECTOR (VARCHAR), TITLE (VARCHAR), YEAR (INTEGER). Man kann aber die Spaltentitel mit der Annotation @Column auch selbst bestimmen.

Der MovieHandler


Diese Klasse stellt die notwendigen Methoden bereit um die Tabelle zu bearbeiten.

/*
   ermöglicht aufnehmen, löschen und ausgeben
   in die tabelle, die zur entity Movie gehört
*/

import java.util.List;
import javax.persistence.Query;
import javax.persistence.EntityManager;

public class MovieHandler
{
   private EntityManager em;

   public MovieHandler(EntityManager entityManager)
      throws IllegalArgumentException
   {
      if (entityManager == null)
         throw new IllegalArgumentException("entityManager cannot be null");

      em = entityManager;
   }

   public void addMovie(Movie movie)
   {
      em.getTransaction().begin();
      em.persist(movie);
      em.getTransaction().commit();
   }

   public boolean deleteMovie(Object primaryKey)
   {
      Movie movie = em.find(Movie.class,primaryKey) ;
      if (movie!=null)
      {
         em.remove(movie);
         return true;
      }
      return false;
   }

   public List<Movie> listMovies()
   {
      Query query = em.createQuery("SELECT m from Movie as m");
      return query.getResultList();
   }
} // end MovieHandler

Die Klasse arbeitet mit dem EntityManager zusammen. Dieser stellt die notwendigen Methoden bereit um auf die datenbank zuzugreifen, nachdem die Tabelle érstellt worden ist. Für Datenbankabfragen gibt es eine eigne Abfragesprache, Java Persistence Query Language, siehe hierzu den Wikipediaeintrag.

Die Mainklasse ConnectToMovieDB


/*
   Main class
   arbeitet zusammen mit Movie, MovieHandler, persistence.xml

   um die anwendung laufen zu lassen braucht man

   javaee.jar
   toplink-essentials.jar
   toplink-essentials-agent.jar
   mysql-connector-java-5.1.12-bin.jar

   szenario 1
   -----------------
   startet man über textpad, so müssen die dateien um ext-verzeichnis des jdk liegen
   startet man über die konsole oder eclipse, so müssen die dateien im ext-verzeichnis der jre liegen

   szenario 2
   -----------------
   man erstellt ein startbares jar-file.
   aufruf mit

   java -jar <myJarName>.jar

   beim aufruf erzeugt der manager die beiden hilfsdateien
      createDDL.jdbc
      dropDDL.jdbc

   sie enthalten die SQL-statements zum anlegen und ändern der tabellen
*/

import java.util.List;
import java.util.Iterator;
import javax.persistence.Query;
import javax.persistence.Persistence;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

public class ConnectToMovieDB
{
   private static String PERSISTENCE_UNIT_NAME = "movies";
   private static EntityManagerFactory emf;
   private static EntityManager em;

   public static void main(String[] args)
   {
      em = createEntityManager();
      System.out.println("EntityManager = " + em.getClass().getName());
      MovieHandler mh = new MovieHandler(em);

      List<Movie< list = mh.listMovies();
      printMovies(list);

      Movie movie = new Movie("fritz lang","metropolis", 1927);
      mh.addMovie(movie);

      list = mh.listMovies();
      printMovies(list);

      close();
   }

   private static EntityManager createEntityManager()
   {
      String PERSISTENCE_UNIT_NAME = "movies";
      System.out.println("---- about to create EntityManagerFactory ----");
      emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
      System.out.println("EntityManagerFactory = " + emf.getClass().getName());


      System.out.println("------- about to create EntityManager --------");
      return emf.createEntityManager();  // ergibt ein warning
   }


   private static void close()
   {
      System.out.println("------------ close EntityManager -------------");
      em.close();
      System.out.println("--------- close EntityManagerFactory ---------");
      emf.close();
   }


   public static void printMovies(List list)
   {
      if( list.size() == 0)
      {
         System.out.println("--------- no movies in the database ----------");
         return;
      }

      Iterator iter = list.iterator();
      while(iter.hasNext())
      {
         Movie movie = (Movie)iter.next();
         System.out.println(movie.getId() );
         System.out.println(movie.getDirector() );
         System.out.println(movie.getTitle() );
         System.out.println(movie.getYear() );
      }
   }

} // end ConnectToMovieDB


Die Datei persistence.xml


In dieser Datei wird der Zugriff auf die datenbank konfiguriert.

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">

   <persistence-unit name="movies" transaction-type="RESOURCE_LOCAL">
      <provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
      <class>Movie</class>
      <properties>
         <property name="toplink.jdbc.url" value="jdbc:mysql://localhost:3306/test"/>
         <property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver"/>
         <property name="toplink.jdbc.user" value="myPW"/>
         <property name="toplink.jdbc.password" value="myPW"/>
         <property name="toplink.ddl-generation" value="drop-and-create-tables"/>
      </properties>
   </persistence-unit>

</persistence>

Damit haben wir alle Bausteine erstellt. Der Datenbanktreiber muß genauso wie die anderen erwähnten Archive im passenden ext-Verzeichnis (jre und/oder jdk) liegen oder über einen CLASSPATH bekanntgemacht werden.

Screenshot des Ablaufs




2) Entity wird auf remote Datenbanktabelle abgebildet (MySQL)


Für unser zweites Beispiel können wir alle Javaklassen des vorigen Beispiels übernehmen. Lediglich die Datei persistence.xml muß angepaßt werden. Hier die veränderte Datei.

Die Datei persistence.xml


Wir müssen hier nur die neue IP-Adresse eintragen, alles andere bleibt wie vorher.

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">

   <persistence-unit name="movies" transaction-type="RESOURCE_LOCAL">
      <provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
      <class>Movie</class>
      <properties>
         <property name="toplink.jdbc.url" value="jdbc:mysql://<my-server-ip>:3306/test"/>
         <property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver"/>
         <property name="toplink.jdbc.user" value="myPW"/>
         <property name="toplink.jdbc.password" value="myPW"/>
         <property name="toplink.ddl-generation" value="drop-and-create-tables"/>
      </properties>
   </persistence-unit>

</persistence>

Man beachte, daß der Datenbanktreiber beim Client liegt.

Remote-Zugriff erlauben


Auf dem Server muß MySQL so konfiguriert sein, daß auch nichtlokale Zugriffe erlaubt sind. Wir starten daher die Konfigurierung erneut und verändern die Einstellung wie folgt:




Screenshot des Ablaufs


Der Screenshot unterscheidet sich nicht vom vorigen Beispiel.


top Back Next Up Home