Java EE: JAX-RS, EJB en JPA (EclipseLink / Mysql) mbv annotaties.

In de meeste gevallen kom ik als javaan ergens binnen om aan bestaande functionaliteit te werken. Maar, het leukste blijft toch om alles ‘from scratch’ bouwen.

In dit artikel niet zozeer een verhaal over nieuwe technieken, of mijn ‘from scratch’ aanpak, maar simpelweg een stuk voorbeeld code + uitleg om te laten zien hoe gemakkelijk de technieken uit de titel zijn in te zetten.

Als eerste wat context

Om het geheugen op te frissen, of om wat gaten in te vullen, van links naar rechts:

JAX-RS is een api waarmee REST webservices gemaakt kunnen worden. Deze vorm van webservices is met name populair omdat het gebouwd is op de HTTP/1.1 specificatie waardoor het super gemakkelijk te begrijpen is, of aan te sluiten aan je frontend. (Zie @Specificatie, @Wikipedia). (Sinds EE5)

EJB of”Enterpsie JavaBeans’ zijn bedoeld voor je applicatie logica en draaien binnen een EJB container op je applicatieserver. De EJB schrijft o.a. voor hoe omgegaan dient te worden met zaken als trancties, concurrency en security. Het schrijven van EJB’s is pas echt een feest sinds EJB 3.0 waar annotaties de warboel van deployment descriptors en interfaces hebben vervangen. (@Wikipedia)

JPA of ‘Java Persistence API’ is een een specificatie die beschrijft hoe van uit Java met (relationele) data omgegaan dient te worden. Met JPA breng je een object-relational-mapping tot stand o.b.v. annotaties.  JPA kent een aantal implementaties waarvan de bekendste wellicht Hibernate is.

EclipseLink is de ‘referentie implementatie’ voor JPA en is (net zoals overigens Hibernate) volledig JPA 2.0 complient.  (@EclipseLink FAQ, @Wikipedia)

MySQL is ‘s werelds meest gebruikte opensource RDBMS. En vergt volgens mij geen verdere toelichting.

De implementatie

Welnu, de voorbeeld implementatie betreft een denkbeeldig onderdeel van een beheerplatform. Het stukje ‘UserManagement’ is bedoeld om informatie van gebruikers van ‘het systeem’ aan te maken, of te raadplegen.

De demo bestaat uit een Stateless Session Bean (SSB) ‘UserManagement’ die met zijn twee methoden (t.b.v create/retreive) beschikbaar wordt gesteld via JAX-RS. De User objecten worden gemanaged, opgehaald en opgeslagen in MySQL d.m.v. EclipseLink.

1. Structuur / overzicht

Om te beginnen hieronder een overzicht van het project. In dit project zit geen web.xml, alle configuratie gebeurt o.b.v. annotaties.

Java EE JAX-RS, EJB and JPA (EclipseLink Mysql)  mbv annotaties.

2. EclipseLink & Mysql configuratie

De basisconfiguratie van JPA wordt gevormd door persistence.xml. Hierin configureer je ‘Persistence Units’. Een persistent unit is een groep van ‘persistable classes’ met bijbehorende configuratie.

<persistence-unit name="default" transaction-type="JTA">
	<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

	<jta-data-source>java:app/ee6sample/SampleDS</jta-data-source>

	<exclude-unlisted-classes>false</exclude-unlisted-classes>

	<properties>
		<property name="eclipselink.ddl-generation" value="create-tables" />
		<property name="eclipselink.ddl-generation.output-mode"	value="database" />
	</properties>
</persistence-unit>

In bovenstaand voorbeeld configureren we een persisten-unit met de naam ‘default’. Het ‘transaction-type’ JTA (@wiki) wordt afgedwongen doordat we JPA binnen de EJB managed context gebruiken.

We gebruiken EclipseLink (<provider/>) en maken gebruik van de ‘java:app/ee6sample/SampleDS’ datasource (zie volgend onderdeel).

Waar je normaal gesproken met <class/> configureert welke klassen bij deze persistence-unit horen, geven we in dit voorbeeld aan dat niet geconfigureerde klassen opgenomen kunnen worden in deze PU. Met slechts één PU laten we alle klassen dus managen door default. (exclude-unlisted-classes = false).

Aanvullend specificeren we dat de DDL voor de tabellen direct op de databases uit laten voeren. Anders verwoord, JPA gaat de tabellen aanmaken voor onze applicatie.

3. Datasources.java – Datasource registratie m.b.v. annotaties

Sinds JSR-250 is er de mogleijkheid om datasources te regiteren met behulp van de annotaties @DataSourceDefinition en @DataSourceDefinitions. Voorheen was het altijd nodig om deze configuratie in de applicatie server uit te voeren, maar nu wordt deze configuratie dus portable.

Onderstaand codevoorbeeld registreert een datasource in de applicatie scope.

package nl.ivojonker.ee6sample.configuration;

import javax.annotation.sql.DataSourceDefinition;


/**
 * Registers the following datasources: 
 * 		java:app/ee6sample/SampleDS
 * 
 * web.xml allow's to override the defaults.
 * @author ivo.jonker
 */

@DataSourceDefinition(
		name = "java:app/ee6sample/SampleDS",
		className = "com.mysql.jdbc.jdbc2.optional.MysqlXADataSource",
		url = "jdbc:mysql://localhost:3306/ivo",
		user = "root",
		password = "") 

public class Datasources {

}

Deze configuratie valt uiteraard onder de noemer ‘hard-coded’, maar kan eventueel worden overriden in de web.xml

4. User.java – een JPA managed entiteit

De klasse User is een POJO geannoteerd met @Entity waarmee we zeggen dat dit een door ‘JPA gemanagde entiteit’ is. Met de aangebrachte annotatie zal deze entiteit corresponderen met de  tabel User (ID int(11) primary key, NAME varchar(255)) .

De tabel – indien hij niet bestaat – zal automatisch worden aangemaakt door EclipseLink. Waarden voor ID zullen automatisch worden gegenereerd (@Id).

package nl.ivojonker.ee6sample.model;

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

@Entity
public class User {

	@Id
	@GeneratedValue
	private int id;
	
	private String name;

	public int getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

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

Uiteraard zijn er veel meer annotaties en instellingen, een mooi overzicht vondt ik op de website van de ObjectDB JPA implementatie.

 5. UserManagement.java – een JAX-RS exposed SSB met een EntityManager

De klasse UserManagement bevat de business logica voor het managen van users. In dit geval een Stateless Session Bean (@Stateless) met twee methoden. Een om een user mee aan te maken, een andere om user-gegevens op te vragen a.d.h.v. een user id. Beide methoden worden aangeboden via JAX-RS webservices. De annotaties spreken voor zich wanneer je beseft dat ze het volgende mogelijk maken:

HTTP PUT http://localhost:8080/Demo/rest/users?name=Ivo
Om een nieuwe gebruiker aan te maken

HTTP GET http://localhost:8080/Demo/rest/users?id=1
Om een gebruikergegevens met id 1 op te halen uit de database.

Met @PersistenceContext injecteren we een container-managed entity manager. Deze gebruiken we vervolgens om nieuwe Users aan te maken of terug te halen uit de database.

Naast de @QueryParam kun je ook nog annotaties als  @MatrixParam, @HeaderParam, @CookieParam, @FormParam gebruiken om b.v. headers of cookiers te benaderen.

package nl.ivojonker.ee6sample.logic;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;

import nl.ivojonker.ee6sample.model.User;

@Stateless
@Path("/users")
@Produces("text/plain")
public class UserManagement {
	
	@PersistenceContext
	EntityManager em;

	@GET
	public String getUser(@QueryParam("id") int id){
		User user = em.find(User.class, id);
		return "username: "+user.getName();
	}
	
	@PUT
	public String createUser(@QueryParam("name") String name){
		User newUser = new User();
		newUser.setName(name);
		
		em.persist(newUser);
		
		return "New user created with id: "+newUser.getId();
	}
}

 6. JerseyConfig.java

Jersey is JAX-RS implementatie die zich erg gemakkelijk laat configureren.  In het voorbeeld doen we dit met een annotatie waarmee we alle classes in de nl.ivojonker.ee6sample.logic package exposen binnen het rest path.

Alternatief laat Jersey zich ook prima in de web.xml file configuren.

package nl.ivojonker.ee6sample.configuration;

import javax.ws.rs.ApplicationPath;

import org.glassfish.jersey.server.ResourceConfig;

/**
 * Registers the JAX-rs path rest for classes within the nl.ivojonker.* package.
 * @author ivo.jonker
 *
 */
@ApplicationPath("rest")
public class JerseyConfig extends ResourceConfig {

    public JerseyConfig() {
        packages("nl.ivojonker.ee6sample.logic");
    }
}

Makkelijk toch?

 

Leave a Reply

Your email address will not be published. Required fields are marked *