Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "EclipseLink/Examples/MySports"

(Persistence)
 
(47 intermediate revisions by 4 users not shown)
Line 1: Line 1:
= EclipseLink MySports Example =
+
<div style="float:right;width:300px"><div style="background:#ffffff;width:275px" align="center">[[Image:EclipseLink_Mysports.png]]__TOC__</div></div>
  
The MySports example is a simple web application which demonstrates several key features of
+
In this example users can view and modify information for multiple sports leagues including extended attributes with the additional mapping information stored in an external source.
<div style="float:right;width:300px">
+
 
<div style="background:#ffffff;width:275px" align="center">
+
The MySports example is a web application which demonstrates EclipseLink's latest features:
[[Image:EclipseLink_Mysports.png]]
+
* '''Multi-tenancy''' (Tenant isolation): The application can be deployed as a SaaS solution with multiple leagues being hosted by a common application instance and a shared database with the choice of:
__TOC__
+
** @Multitenant(SINGLE_TABLE) - row level isolation using LEAGUE_ID column values
</div>
+
** @Multitenant(TABLE_PER_TENANT) - separate tables using league id as table name suffix
</div>
+
* '''Extensibility''': Each League's divisions, teams, and players can be extended dynamically to store and support querying of additional administrator defined properties.
EclipseLink including:  
+
* External Metadata: Using the JPA and JAXB MetadataSource capabilities the tenant specific extensions and mapping definitions are stored in the MySports Admin application enabling dynamic league provisioning and customization.
 +
* '''EMF per Tenant''': Extends EclipseLink to construct a separate EMF for each hosted league.
 +
* '''JPA-RS''': Excposes both the MySposrts and MySports Admin apps using REST
  
*EclipseLink JPA
 
**@Multitenant(SINGLE_TABLE)
 
**Extensible entities with @VirtualAccessMethods
 
  
 
== Example Overview ==
 
== Example Overview ==
 +
The MySports example includes the following projects:
 +
'''MySports''': A dynamic web project which deploys the primary application, exposing a JSF and JAX-RS (REST) front-end.
  
The example includes 3 projects
+
'''MySports Admin''': Administration console for the project.
  
#MySports: A Dynamic Web project which deploys the primary application exposing a JSF and
+
'''MySports Tests''': A Java project containing Junit tests that verifies the functionality of the example and creates the necessary database tables
  
JAX-RS (REST) front end.
+
== Installation and Configuration  ==
  
#MySports Admin:
+
In order to setup and run this example the following install and configure steps must be followed carefully.
#MySports Tests: A Java project containing Junit tests that verify the functionality of
+
  
== Install & Config ==
+
The MySports application is developed within its own . Using any GIT tools the example can be checked out anonymously.
  
At present the example is only available through SVN access. When completed a ZIP download will be made available.
+
=== Prequisites ===
 +
To run the MySports example, you will need the following:
 +
# GlassFish 3.1.2  (http://glassfishplugins.java.net/eclipse36/)
 +
# Eclipse Java EE IDE with GlassFish adapter (http://www.eclipse.org/downloads/)
 +
#* Example has projects setup for Eclipse usage but code should be usable in any development environment.
 +
# EclipseLink 2.4 Bundles ([http://www.eclipse.org/eclipselink/releases/2.4.php])
  
Basic Steps
+
=== Basic Steps ===
# Prepare Prerequisites:  
+
 
## GlassFish 3.1
+
# Clone the [http://git.eclipse.org/c/eclipselink/examples/mysports.git/ MySports GIT repositiory]
## Eclipse Java EE with GlassFish adapter
+
# Upgrade GlassFish to use EclipseLink 2.4 [[EclipseLink/Examples/MySports/GlassFish]]
# Configure Eclipse
+
## Ensure GlassFish server is configured
## Requires a variable named 'eclispelink_2.3_jar' for the javaagent usage of the test project
+
## Configure a jdbc/MySports JDBC resource and supporting connection pool to a MySQL database
## Ensure you have a GlassFish Server configured in the Java EE perspective
+
# Open the MySports projects in Eclipse
# Configure GlassFish
+
## Configure Eclipse - [[EclipseLink/Examples/MySports/Eclipse]]
## EclipseLink 2.3 bundles installed in GlassFish
+
## Fix any project library dependencies on GlassFish and target server
## A connection pool named 'jdbc/MySports' must be defined in the server
+
# Customize MySports Tests/eclipselink-example-mysports.properties to point to the same MySQL database as connection pool in GlassFish
# Get the example's projects
+
# Run MySports AllTests run target. This will setup the table and populate the initial leagues
#* http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/trunk/examples/my-sports/MySports/
+
#* http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/trunk/examples/my-sports/MySportsAdmin/
+
#* http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/trunk/examples/my-sports/MySportsTests/
+
## Import the projects
+
## Customize the '''eclipselink-examples-mysports.properties''' file for your database
+
# Run The example
+
## Run the '''MySports AllTests''' launch target. This will create the database tables and prepare an initial population
+
## Run the '''MySports Admin''' application
+
## Run the '''MySports''' application
+
  
 
== Example Details ==
 
== Example Details ==
  
=== MySports Domain ===
+
=== MySports Domain (example.mysports.model) ===
  
The domain model is that of any arbitrary sports league. The idea is that this SaaS
+
The domain model is that of any arbitrary sports league. The intent is to build an application that captures the state of an arbitrary league and use it in a multitenant application where multiple leagues (tenants) can be hosted. The domain model is intentionally unaware of the potential support for multiple leagues and therefore only models entities that exist within an individual league.
 
+
solution allows any league to host its information on the site and customize the data
+
 
+
stored as well as the look and feel.  
+
  
 
{|{{BMTableStyle}}
 
{|{{BMTableStyle}}
 
|-{{BMTHStyle}}
 
|-{{BMTHStyle}}
! Class
+
! Class/Interface
 
! Description
 
! Description
 
|-
 
|-
 
| Division  
 
| Division  
| A league contains one or more divisions of teams used to divide teams by age, skill or simply to manage a larger set of teams.
+
| <source lang="java">
 +
@Entity
 +
@Table(name = "mys_div")
 +
@Multitenant(MultitenantType.SINGLE_TABLE)
 +
@TenantDiscriminatorColumn(name = "LEAGUE_ID", contextProperty = LEAGUE_CONTEXT)
 +
@NamedQueries({
 +
    @NamedQuery(name="Division.findAll", query="SELECT d FROM Division d ORDER BY d.name",
 +
                hints={@QueryHint(name=QueryHints.QUERY_RESULTS_CACHE, value=HintValues.TRUE)}),
 +
    @NamedQuery(name="Division.findByName", query="SELECT d FROM Division d WHERE d.name = :NAME")
 +
})
 +
public class Division implements Extensible {
 +
</source>
 
|-
 
|-
 
| Team
 
| Team
| A team belongs to a division and has a name and players.
+
| <source lang="java">
 +
@Entity
 +
@Table(name = "mys_team")
 +
@Multitenant(MultitenantType.SINGLE_TABLE)
 +
@TenantDiscriminatorColumn(name = "LEAGUE_ID", contextProperty = LEAGUE_CONTEXT)
 +
@NamedQuery(name="Team.findByDivisionAndName", query="SELECT t FROM Team t WHERE t.name = :NAME AND t.division.name = :DIV")
 +
public class Team implements Extensible {
 +
</source>
 
|-
 
|-
 
| Player
 
| Player
| A player represents a person within a specified team. A player is an extensible entity type.
+
| <source lang="java">
 +
/**
 +
* In the MySports demo a Player entity represents an individual member of a
 +
* team. The Player entity is both multitenant and extensible.
 +
*/
 +
@Entity
 +
@Table(name = "mys_player")
 +
@Multitenant(MultitenantType.SINGLE_TABLE)
 +
@TenantDiscriminatorColumn(name = "LEAGUE_ID", contextProperty = LEAGUE_CONTEXT)
 +
@VirtualAccessMethods
 +
public class Player implements Extensible {
 +
</source>
 +
|-
 +
| Extensible
 +
| An application interface used to indicate extensible types and enable their use in the presentation tier. This interface is not required or used by EclipseLink.
 +
|-
 +
| Divisions
 +
| A non-entity container class used for returning multiple divisions from a JAX-RS call to enable the MOXy marshalling into XML.
 
|}
 
|}
 
  
 
=== Persistence ===
 
=== Persistence ===
Line 80: Line 106:
 
The persistence layer is the main purpose of this example application. The persistence layer makes use of application bootstrapped persistence contexts with support for an EntityManagerFactory and backing ServerSession (with Cache) per league (tenant). This all bootstrapped off of a single persistence-unit definition.
 
The persistence layer is the main purpose of this example application. The persistence layer makes use of application bootstrapped persistence contexts with support for an EntityManagerFactory and backing ServerSession (with Cache) per league (tenant). This all bootstrapped off of a single persistence-unit definition.
  
[[Image:Mysports_persistence.png]]
+
 
 +
==== LeagueRepository ====
 +
 
 +
The LeagueRepository is the primary persistence abstraction responsible for league (tenant) specific persistence access managing both JPA persistence units and the MOXy JAXBContext.
 +
 
 +
==== JPA Usage ====
 +
 
 +
The persistence layer makes use of standard JPA 2.0 API plus some EclipseLink specific extensions to support:
 +
* Multi-tenancy - augment the SQL to limit results to current tenant or leverage Oracle VPD to do SQL augmentation
 +
* Extensible Entities - support additional tenant specific attributes on entities
 +
* External Metadata Source - retrieve tenant specific extension definitions for JPA and JAXB from JAX-RS admin service
 +
* '''EMF per Tenant''': EMF created per tenant with a single shared persistence unit definition
 +
 
 +
===== Multi-Tenancy =====
 +
 
 +
The configuration that enables multi-tenancy usage is the @Multitenant annotation that is specified on one or more entities. In this example application Player, Team, and Division are multitenant and are each configured using:
 +
 
 +
<source lang="java">
 +
@Multitenant(MultitenantType.SINGLE_TABLE)
 +
@TenantDiscriminatorColumn(name = "LEAGUE_ID", contextProperty = LEAGUE_CONTEXT)
 +
</source>
 +
 
 +
This specifies that the entities for multiple tenants are stored in a shared table and that the access to this table must limit its results to a specific tenant using the LEAGUE_ID column and the context property value specified by the LEAGUE_CONTEXT ("mysports.league").
 +
 
 +
'''Oracle VPD'''
 +
By default this example application will augment all generated SQL for SELECT, UPDATE, and DELETE to add in an additional comparison for the LEAGU_ID column. With INSERT operations the LEAGUE_ID column will be populated. Alternatively the example application can be configured to use Oracle VPD to handle the SELECT, UPDATE, DELETE SQL additions within the database. To setup and configure the demo application to use Oracle VPD you must be using an Oracle database and must set the mysports.vpd=true in the application's src folder and test's src folder.
 +
 
 +
===== Extensible Entities =====
 +
 
 +
The entities (Player, Team, and Division) in this example are extensible. This means additional attribute mappings can be dynamically defined. In this case the extensions are tenant specific and the definitions are maintained within the admin application. To make an entity extensible you can use annotations like:
 +
 
 +
<source lang="java">
 +
@VirtualAccessMethods
 +
public class Player implements Extensible {
 +
</source>
 +
 
 +
This indicates that the default get and set methods will be used. The Extensible interface is not required by EclipseLink but is used in the application to identify classes that support extensions. Within the entity classes the get and set methods along with a dat structure to store the extended values must be provided.
 +
 
 +
<source lang="java">
 +
@Transient
 +
private Map<String, Object> attributes = new HashMap<String, Object>();
 +
 
 +
@SuppressWarnings("unchecked")
 +
public <T> T get(String attributeName) {
 +
    return (T) this.attributes.get(attributeName);
 +
}
 +
 
 +
public Object set(String attributeName, Object value) {
 +
    return this.attributes.put(attributeName, value);
 +
}
 +
</source>
 +
 
 +
===== External Metadata Source =====
 +
 
 +
The extensions definitions are maintained externally in the Admin application which is accessed using JAX-RS calls. The example application provides an implementation of MetadataSource for both JPA and MOXy. For JPA this source is configured using a persistence unit property in the persistence.xml.
 +
 
 +
<source lang="xml">
 +
<property name="eclipselink.metadata-source" value="example.mysports.admin.AdminMetadataSource"/>
 +
</source>
 +
 
 +
=====EMF per Tenant =====
 +
 
 +
When developing an application that can handle requests from multiple tenants you can choose to have a single EntityManager Factory (EMF) with tenant scoped EntityManagers (EM) or you can choose to have a EMF per tenant. The decision really comes down to the number of tenants and the value of maintaining a cache that can be shared upon user requests for the same tenant and any usage of extended attributes per tenant. In this example application where there extensions per tenant and a limited number of tenants the decision was made to use an EMF per tenant.
 +
 
 +
[[EclipseLink/Examples/MySports/EMFperTenant | Lear more...]]
 +
 
 +
==== JPA-RS ====
 +
 
 +
The REST interface for MySports is provided by EclipseLink JPA-RS.

Latest revision as of 13:54, 21 June 2012

In this example users can view and modify information for multiple sports leagues including extended attributes with the additional mapping information stored in an external source.

The MySports example is a web application which demonstrates EclipseLink's latest features:

  • Multi-tenancy (Tenant isolation): The application can be deployed as a SaaS solution with multiple leagues being hosted by a common application instance and a shared database with the choice of:
    • @Multitenant(SINGLE_TABLE) - row level isolation using LEAGUE_ID column values
    • @Multitenant(TABLE_PER_TENANT) - separate tables using league id as table name suffix
  • Extensibility: Each League's divisions, teams, and players can be extended dynamically to store and support querying of additional administrator defined properties.
  • External Metadata: Using the JPA and JAXB MetadataSource capabilities the tenant specific extensions and mapping definitions are stored in the MySports Admin application enabling dynamic league provisioning and customization.
  • EMF per Tenant: Extends EclipseLink to construct a separate EMF for each hosted league.
  • JPA-RS: Excposes both the MySposrts and MySports Admin apps using REST


Example Overview

The MySports example includes the following projects: MySports: A dynamic web project which deploys the primary application, exposing a JSF and JAX-RS (REST) front-end.

MySports Admin: Administration console for the project.

MySports Tests: A Java project containing Junit tests that verifies the functionality of the example and creates the necessary database tables

Installation and Configuration

In order to setup and run this example the following install and configure steps must be followed carefully.

The MySports application is developed within its own . Using any GIT tools the example can be checked out anonymously.

Prequisites

To run the MySports example, you will need the following:

  1. GlassFish 3.1.2 (http://glassfishplugins.java.net/eclipse36/)
  2. Eclipse Java EE IDE with GlassFish adapter (http://www.eclipse.org/downloads/)
    • Example has projects setup for Eclipse usage but code should be usable in any development environment.
  3. EclipseLink 2.4 Bundles ([1])

Basic Steps

  1. Clone the MySports GIT repositiory
  2. Upgrade GlassFish to use EclipseLink 2.4 EclipseLink/Examples/MySports/GlassFish
    1. Ensure GlassFish server is configured
    2. Configure a jdbc/MySports JDBC resource and supporting connection pool to a MySQL database
  3. Open the MySports projects in Eclipse
    1. Configure Eclipse - EclipseLink/Examples/MySports/Eclipse
    2. Fix any project library dependencies on GlassFish and target server
  4. Customize MySports Tests/eclipselink-example-mysports.properties to point to the same MySQL database as connection pool in GlassFish
  5. Run MySports AllTests run target. This will setup the table and populate the initial leagues

Example Details

MySports Domain (example.mysports.model)

The domain model is that of any arbitrary sports league. The intent is to build an application that captures the state of an arbitrary league and use it in a multitenant application where multiple leagues (tenants) can be hosted. The domain model is intentionally unaware of the potential support for multiple leagues and therefore only models entities that exist within an individual league.

Class/Interface Description
Division
@Entity
@Table(name = "mys_div")
@Multitenant(MultitenantType.SINGLE_TABLE)
@TenantDiscriminatorColumn(name = "LEAGUE_ID", contextProperty = LEAGUE_CONTEXT)
@NamedQueries({
    @NamedQuery(name="Division.findAll", query="SELECT d FROM Division d ORDER BY d.name",
                hints={@QueryHint(name=QueryHints.QUERY_RESULTS_CACHE, value=HintValues.TRUE)}),
    @NamedQuery(name="Division.findByName", query="SELECT d FROM Division d WHERE d.name = :NAME")
})
public class Division implements Extensible {
Team
@Entity
@Table(name = "mys_team")
@Multitenant(MultitenantType.SINGLE_TABLE)
@TenantDiscriminatorColumn(name = "LEAGUE_ID", contextProperty = LEAGUE_CONTEXT)
@NamedQuery(name="Team.findByDivisionAndName", query="SELECT t FROM Team t WHERE t.name = :NAME AND t.division.name = :DIV")
public class Team implements Extensible {
Player
/**
 * In the MySports demo a Player entity represents an individual member of a
 * team. The Player entity is both multitenant and extensible.
 */
@Entity
@Table(name = "mys_player")
@Multitenant(MultitenantType.SINGLE_TABLE)
@TenantDiscriminatorColumn(name = "LEAGUE_ID", contextProperty = LEAGUE_CONTEXT)
@VirtualAccessMethods
public class Player implements Extensible {
Extensible An application interface used to indicate extensible types and enable their use in the presentation tier. This interface is not required or used by EclipseLink.
Divisions A non-entity container class used for returning multiple divisions from a JAX-RS call to enable the MOXy marshalling into XML.

Persistence

The persistence layer is the main purpose of this example application. The persistence layer makes use of application bootstrapped persistence contexts with support for an EntityManagerFactory and backing ServerSession (with Cache) per league (tenant). This all bootstrapped off of a single persistence-unit definition.


LeagueRepository

The LeagueRepository is the primary persistence abstraction responsible for league (tenant) specific persistence access managing both JPA persistence units and the MOXy JAXBContext.

JPA Usage

The persistence layer makes use of standard JPA 2.0 API plus some EclipseLink specific extensions to support:

  • Multi-tenancy - augment the SQL to limit results to current tenant or leverage Oracle VPD to do SQL augmentation
  • Extensible Entities - support additional tenant specific attributes on entities
  • External Metadata Source - retrieve tenant specific extension definitions for JPA and JAXB from JAX-RS admin service
  • EMF per Tenant: EMF created per tenant with a single shared persistence unit definition
Multi-Tenancy

The configuration that enables multi-tenancy usage is the @Multitenant annotation that is specified on one or more entities. In this example application Player, Team, and Division are multitenant and are each configured using:

@Multitenant(MultitenantType.SINGLE_TABLE)
@TenantDiscriminatorColumn(name = "LEAGUE_ID", contextProperty = LEAGUE_CONTEXT)

This specifies that the entities for multiple tenants are stored in a shared table and that the access to this table must limit its results to a specific tenant using the LEAGUE_ID column and the context property value specified by the LEAGUE_CONTEXT ("mysports.league").

Oracle VPD By default this example application will augment all generated SQL for SELECT, UPDATE, and DELETE to add in an additional comparison for the LEAGU_ID column. With INSERT operations the LEAGUE_ID column will be populated. Alternatively the example application can be configured to use Oracle VPD to handle the SELECT, UPDATE, DELETE SQL additions within the database. To setup and configure the demo application to use Oracle VPD you must be using an Oracle database and must set the mysports.vpd=true in the application's src folder and test's src folder.

Extensible Entities

The entities (Player, Team, and Division) in this example are extensible. This means additional attribute mappings can be dynamically defined. In this case the extensions are tenant specific and the definitions are maintained within the admin application. To make an entity extensible you can use annotations like:

@VirtualAccessMethods
public class Player implements Extensible {

This indicates that the default get and set methods will be used. The Extensible interface is not required by EclipseLink but is used in the application to identify classes that support extensions. Within the entity classes the get and set methods along with a dat structure to store the extended values must be provided.

@Transient
private Map<String, Object> attributes = new HashMap<String, Object>();
 
@SuppressWarnings("unchecked")
public <T> T get(String attributeName) {
    return (T) this.attributes.get(attributeName);
}
 
public Object set(String attributeName, Object value) {
    return this.attributes.put(attributeName, value);
}
External Metadata Source

The extensions definitions are maintained externally in the Admin application which is accessed using JAX-RS calls. The example application provides an implementation of MetadataSource for both JPA and MOXy. For JPA this source is configured using a persistence unit property in the persistence.xml.

<property name="eclipselink.metadata-source" value="example.mysports.admin.AdminMetadataSource"/>
EMF per Tenant

When developing an application that can handle requests from multiple tenants you can choose to have a single EntityManager Factory (EMF) with tenant scoped EntityManagers (EM) or you can choose to have a EMF per tenant. The decision really comes down to the number of tenants and the value of maintaining a cache that can be shared upon user requests for the same tenant and any usage of extended attributes per tenant. In this example application where there extensions per tenant and a limited number of tenants the decision was made to use an EMF per tenant.

Lear more...

JPA-RS

The REST interface for MySports is provided by EclipseLink JPA-RS.

Copyright © Eclipse Foundation, Inc. All Rights Reserved.