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/DesignDocs/328404 new"

(Concepts)
(Persistence Unit Properties)
 
(76 intermediate revisions by 2 users not shown)
Line 4: Line 4:
  
 
[http://bugs.eclipse.org/328404 ER 328404]
 
[http://bugs.eclipse.org/328404 ER 328404]
 
 
== Document History ==
 
== Document History ==
 +
[[EclipseLink/DesignDocs/328404| old version of the doc]]
 
{|{{BMTableStyle}}
 
{|{{BMTableStyle}}
 
|-{{BMTHStyle}}
 
|-{{BMTHStyle}}
Line 33: Line 33:
 
'''Terminology'''
 
'''Terminology'''
 
* '''Data Source''': For the purposes of this discussion a data-source will include JTA and non-JTA data sources as well as EclipseLink's native JDBC connection pools.  
 
* '''Data Source''': For the purposes of this discussion a data-source will include JTA and non-JTA data sources as well as EclipseLink's native JDBC connection pools.  
* '''Broker PU''' (or '''Container PU''' or '''Aggregate PU''' - need to choose the name): Refers to a PU which combines 2 or more '''Contained PUs''' to provide a persistence context which allows queries and transactions (with limitations) across the combined set of entity types.
+
* '''Composite PU''': Refers to a PU which combines 2 or more '''Composite Member PU'''s to provide a persistence context which allows queries and transactions (with limitations) across the combined set of entity types.
 
+
=== Background===
+
* Currently each persistence unit has a single ServerSession.
+
** ServerSession typically connected to a single data base.
+
*** Even though ServerSession may use connection pools that connected to different data bases these databases always should share the same database platform.
+
**** That means it's impossible to use ServerSession to map different classes to different types of data bases (say, Oracle and MySQL).
+
 
+
* Eclipselink core defines SessionBroker class that aggregates several ServerSessions.
+
** SessionBroker maps each class to a single ServerSession.
+
** Each ServerSession connected to a different data base.
+
*** These ServerSessions are not required to share the same database platform.
+
*** Therefore different classes mapped to different data bases, too.
+
* This feature is going to define persistence unit that has a SessionBroker instead of ServerSession.
+
** Let's call it Container persistence unit (or SessionBroker persistence unit).
+
  
 
== Requirements ==
 
== Requirements ==
Line 57: Line 43:
 
|-  
 
|-  
 
| 1
 
| 1
| Add support for a single persistence context accessing entities stored in different data sources (schemas/table-space/database) where application developers can perform queries and transactions across the complete set of entities transparently.  
+
| Add support for a single persistence context accessing entities stored in different '''Data Source'''s (schemas/table-space/database) where application developers can perform queries and transactions across the complete set of entities transparently.  
 
|-  
 
|-  
 
| 2
 
| 2
| Support mapping relationships between entities in different data sources.
+
| Support mapping relationships between entities in different '''Data Source'''s.
 
|-  
 
|-  
 
| 3
 
| 3
Line 66: Line 52:
 
|-  
 
|-  
 
| 4
 
| 4
| Clearly capture usage limitations and exceptions expected in Java Docs and user documentation. The most basic example of this is the ability to join across tables in different data sources. This limitation effects mapping and query execution and optimizations. These issues need to be identified and documented.
+
| Clearly capture usage limitations and exceptions expected in Java Docs and user documentation. The most basic example of this is the ability to join across tables in different '''Data Source'''s. This limitation effects mapping and query execution and optimizations. These issues need to be identified and documented.
 
|-  
 
|-  
 
| 5
 
| 5
Line 83: Line 69:
 
** {{bug|329185}} - SessionBroker: ClassCastException in Cursor.buildAndRegisterObject between ServerSession and UnitOfWorkImpl  
 
** {{bug|329185}} - SessionBroker: ClassCastException in Cursor.buildAndRegisterObject between ServerSession and UnitOfWorkImpl  
 
** {{bug|332581}} - SessionBroker session event issues to consider and resolve when implementing JPA Session Broker
 
** {{bug|332581}} - SessionBroker session event issues to consider and resolve when implementing JPA Session Broker
 
+
** {{bug|331712}} - Allow Isolated classes to work with client session broker
=== Design/Dev Requirements ===
+
 
+
''Doug: I believe this is more implementation focused and should be moved into design section.''
+
 
+
* SessionBroker persistence unit must be defined in persistence.xml (as any other persistence unit).
+
 
+
* The two main use cases:
+
 
+
** Unify multiple persistence units (with independent from each other object models).
+
*** User starts with several independent persistence units, creates a new SessionBroker persistent unit that aggregates ServerSessions defined in the original persistence units.
+
*** The original persistence units remain unchanged, could still be used individually.
+
*** Limitation: the original persistence units and the SessionBroker persistent unit should be all defined in a single jar file.
+
 
+
** Split single persistent unit.
+
*** User starts with a single persistence unit, alters it to become SessionBroker persistence unit.
+
  
 
== Design Constraints ==
 
== Design Constraints ==
Line 104: Line 75:
 
== Design / Functionality ==
 
== Design / Functionality ==
  
* ServerSessions that are aggregated by a SessionBroker persistence unit are "invisible" outside of it:
+
== Testing ==
** don't have EntityManagerFactories associated with them;
+
* The tests are (as always) in trunk\jpa\eclipselink.jpa.test, they are added to FullRegressionTestSuite.
** EntityManagerSetupImpl used for their creation are not kept;
+
* New test models were defined that mirror some existing test models.
** these sessions are not stored in SessionManager.
+
* Each of the new models was divided into three composite members.
 +
** Division was done in such a way that there are lots of references between classes that belong to different composite members.
 +
* For each new model a new test suite was created that mirrors existing test suite.
 +
* It might be useful to compare the sources of the original and composite versions of mapped classes and tests to see composite specifics and limitations.
 +
* By default all three composite member persistence unit in each model will use the same data base (specified by db.* properties in test.properties file or passed to TestBrowser)
 +
** To test with three different databases, in test.properties file specify
 +
*** either single.db=false - that would cause member_2 and member_3 to use connection parameters specified in their persistence.xml files;
 +
*** or db2.* and db3.* properties (following the pattern of db.* properties).
 +
*** member_1 always uses the main data base (specified by db.* properties in test.properties file or passed to TestBrowser).
 +
=== Annotations ===
 +
* Original
 +
** Source (src)
 +
*** org.eclipse.persistence.testing.models.jpa.advanced.*
 +
*** org.eclipse.persistence.testing.tests.jpa.advanced.EntityManagerJUnitTestSuite
 +
** Persistence Unit "default"
 +
*** Resource
 +
**** eclipselink-annotation-model
 +
*** Model jar file
 +
**** eclipselink-annotation-model.jar
  
* The two main use cases implementations
+
* Composite
 +
** Source (src)
 +
*** org.eclipse.persistence.testing.models.jpa.composite.advanced.*
 +
*** org.eclipse.persistence.testing.models.jpa.composite.advanced.member_1.*
 +
*** org.eclipse.persistence.testing.models.jpa.composite.advanced.member_2.*
 +
*** org.eclipse.persistence.testing.models.jpa.composite.advanced.member_3.*
 +
*** org.eclipse.persistence.testing.tests.jpa.composite.advanced.EntityManagerJUnitTestSuite
 +
** Persistence Unit "composite-advanced"
 +
*** Resource
 +
**** eclipselink-composite-advanced-model
 +
**** eclipselink-composite-advanced-model-member_1
 +
**** eclipselink-composite-advanced-model-member_2
 +
**** eclipselink-composite-advanced-model-member_3
 +
*** Model jar file
 +
**** eclipselink-composite-advanced-model.jar
 +
*** Member jar files
 +
**** eclipselink-composite-advanced-model-member_1.jar
 +
**** eclipselink-composite-advanced-model-member_2.jar
 +
**** eclipselink-composite-advanced-model-member_3.jar
 +
** Members' database objects' (tables and sequences) names
 +
*** prefixed with "MBR1_", "MBR2_", "MBR3_" respectively.
  
** Unify multiple persistence units (with independent from each other object models).
+
=== XML ===
*** The SessionBroker is constructed from the existing member ServerSessions, member descriptors copied to the SessionBroker.
+
* Original
**** This already works.
+
** Source (src)
 +
*** org.eclipse.persistence.testing.models.jpa.xml.advanced
 +
*** org.eclipse.persistence.testing.tests.jpa.xml.advanced.EntityMappingsAdvancedJUnitTestCase
 +
**** to run it with pu "extended-advanced" (uses eclipselink-orm.xml) use -Dorm.testing=eclipselink
 +
** Persistence Unit "default"
 +
*** Resource
 +
**** eclipselink-xml-only-model
 +
*** Model jar file
 +
**** eclipselink-annotation-model.jar
 +
** Persistence Unit "extended-advanced" (uses eclipselink-orm.xml)
 +
*** Resource
 +
**** eclipselinkorm\eclipselink-xml-extended-model
 +
*** Model jar file
 +
**** eclipselink-xml-extended-model.jar
  
** Split single persistent unit.
+
* Composite
*** The existing SessionBroker is split into new member ServerSessions, descriptors and sequences copied into the member ServerSessions.
+
** Source (src)
**** This is new.
+
*** org.eclipse.persistence.testing.models.jpa.xml.composite.advanced.*
 
+
*** org.eclipse.persistence.testing.models.jpa.xml.composite.advanced.member_1.*
* DatabaseSessions.
+
*** org.eclipse.persistence.testing.models.jpa.xml.composite.advanced.member_2.*
** To accommodate SessionBroker all the code in EntityManagerSetupImpl and around (EntityManagerFactoryImpl, EntityManagerImpl, etc.) needs to be changed:
+
*** org.eclipse.persistence.testing.models.jpa.xml.composite.advanced.member_3.*
***type of the session should be changed from ServerSession to DatabaseSessionImpl (already done in prototype).
+
*** org.eclipse.persistence.testing.tests.jpa.composite.xml.composite.advanced.EntityMappingsAdvancedJUnitTestCase
** That opens the door for an option to use DatabaseSessionImpl instead of ServerSession if desired (both in a "simple" and SessionBroker persistence units).
+
**** to run it with pu "xml-extended-composite-advanced" (uses eclipselink-orm.xml) use -Dorm.testing=eclipselink
** Need a new property (eclipselink.jdbc.single-connection ?) with a boolean value (default false) to support DatabaseSessionImpl.
+
** Persistence Unit "xml-composite-advanced"
 
+
*** Resource
== Testing ==
+
**** eclipselink-xml-composite-advanced-model
 +
**** eclipselink-xml-composite-advanced-model-member_1
 +
**** eclipselink-xml-composite-advanced-model-member_2
 +
**** eclipselink-xml-composite-advanced-model-member_3
 +
*** Model jar file
 +
**** eclipselink-xml-composite-advanced-model.jar
 +
*** Member jar files
 +
**** eclipselink-xml-composite-advanced-model-member_1.jar
 +
**** eclipselink-xml-composite-advanced-model-member_2.jar
 +
**** eclipselink-xml-composite-advanced-model-member_3.jar
 +
** Persistence Unit "xml-extended-composite-advanced"
 +
*** Resource
 +
**** eclipselinkorm\eclipselink-xml-extended-composite-advanced-model
 +
**** eclipselinkorm\eclipselink-xml-extended-composite-advanced-model-member_1
 +
**** eclipselinkorm\eclipselink-xml-extended-composite-advanced-model-member_2
 +
**** eclipselinkorm\eclipselink-xml-extended-composite-advanced-model-member_3
 +
*** Model jar file
 +
**** eclipselink-xml-extended-composite-advanced-model.jar
 +
*** Member jar files
 +
**** eclipselink-xml-extended-composite-advanced-model-member_1.jar
 +
**** eclipselink-xml-extended-composite-advanced-model-member_2.jar
 +
**** eclipselink-xml-extended-composite-advanced-model-member_3.jar
 +
** Members' database objects' (tables and sequences) names
 +
*** prefixed with "XML_MBR1_", "XML_MBR2_", "XML_MBR3_" respectively.
  
 
== API ==
 
== API ==
Line 135: Line 180:
 
== Config files ==
 
== Config files ==
  
* Proposed configuration of SessionBroker persistence unit is done entirely through Persistence Unit properties.
+
* '''Composite PU''' must be configured in persistence.xml using property:
** Properties extension usage and naming patterns.
+
 
<source lang="java">
 
<source lang="java">
// Property with set values
+
/**
eclipselink.define.my-set-property.value1 -> ""
+
* Indicates if it's a composite persistence unit ("true").
eclipselink.define.my-set-property.value2 -> ""
+
* The property must be specified in persistence.xml of a composite persistence unit.
...
+
* The property passed to createEntityManagerFactory method or in system properties is ignored.
eclipselink.define.my-set-property.valueN -> ""
+
* Composite persistence unit would contain all persistence units found in jar files specified by <jar-file> elements in persistence.xml.  
 +
*    <jar-file>member1.jar</jar-file>
 +
*    <jar-file>member2.jar</jar-file>
 +
*    <properties>
 +
*        <property name="eclipselink.composite-unit" value="true"/>
 +
*    </properties>
 +
* @see #COMPOSITE_UNIT_MEMBER
 +
* @see #COMPOSITE_UNIT_PROPERTIES
 +
*/
 +
public static final String COMPOSITE_UNIT = "eclipselink.composite-unit";
 +
</source>
  
// Converted to a Set:
+
* '''Composite Member PU''' may specify in persistence.xml that it can't be used as an independent persistence unit:
my-set-property = {value1, value2, ..., valueN};
+
<source lang="java">
 +
/**
 +
* Indicates if the persistence unit must be a member of a composite persistence unit ("true"),
 +
* can't be used as an independent persistence unit.
 +
* That happens if persistence unit has dependencies on other persistence unit(s).
 +
* The property may be specified in persistence.xml.
 +
* The property passed to createEntityManagerFactory method or in system properties is ignored.
 +
* If this property is set to true, EntityManagerFactory still could be created,
 +
* but it can't be connected: an attempt to create entity manager would cause an exception.
 +
* @see #COMPOSITE_UNIT
 +
* @see #COMPOSITE_UNIT_PROPERTIES
 +
*/
 +
public static final String COMPOSITE_UNIT_MEMBER = "eclipselink.composite-unit.member";
 +
</source>
  
// Suggested naming convention:
+
* While creating '''Composite PU''' EntityManagerFactory properties could be passed to '''Composite Member PU'''s:
// let's use "eclipselink.define" prefix for these "value-less" properties.
+
<source lang="java">
 +
/**
 +
* The property may be passed to createEntityManagerFactory method of a composite persistence unit
 +
* to pass properties to member persistence units.
 +
* The value is a map:
 +
* the key is a member persistence unit's name,
 +
* the value is a map of properties to be passed to this persistence unit.
 +
* "eclipselink.composite-unit.properties" -> (
 +
*  ("memberPu1" -> (  "javax.persistence.jdbc.user" -> "user1",
 +
*                          "javax.persistence.jdbc.password" -> "password1",
 +
*                          "javax.persistence.jdbc.driver" -> "oracle.jdbc.OracleDriver",
 +
*                          "javax.persistence.jdbc.url" -> "jdbc:oracle:thin:@oracle_db_url:1521:db",
 +
*                    ) ,
 +
*  ("memberPu2" -> (  "javax.persistence.jdbc.user" -> "user2",
 +
*                          "javax.persistence.jdbc.password" -> "password2"
 +
*                          "javax.persistence.jdbc.driver" -> "com.mysql.jdbc.Driver",
 +
*                          "javax.persistence.jdbc.url" -> "jdbc:mysql://my_sql_db_url:3306/user2",
 +
*                    )
 +
* )
 +
* @see #COMPOSITE_UNIT
 +
*/
 +
public static final String COMPOSITE_UNIT_PROPERTIES = "eclipselink.composite-unit.properties";
 
</source>
 
</source>
  
 +
* Transaction type should be specified in composite persistence unit (transaction types of composite members ignored).
 +
* Data sources should be specified in composite member persistence units (those specified in the composite are ignored).
  
* The two main use cases:
+
=== Example ===
 
+
* compositePu specifies transaction type and server platform. It will contain all persistence units defined in member1.jar and member2.jar files.
** Unify multiple persistence units (with independent from each other object models).
+
There are two predefine independent persistence units:  puABC (that maps classes A, B, C) and puXYZ (that maps classes X, Y, Z).
+
None of A, B, C classes references any of X, Y, Z classes and vise verse.
+
Below are several examples of persistence.xml for SessionBroker persistence unit.
+
 
<source lang="xml">
 
<source lang="xml">
<!--Scenario 1 - simply use puABC and puXYZ exactly as they were originally defined-->
+
<persistence 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 persistence_1_0.xsd" version="1.0">
-<persistence 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 persistence_1_0.xsd" version="1.0">
+
     <persistence-unit name="compositePu" transaction-type="JTA">
     <persistence-unit name="broker" transaction-type="RESOURCE_LOCAL">
+
 
         <provider>
 
         <provider>
 
             org.eclipse.persistence.jpa.PersistenceProvider
 
             org.eclipse.persistence.jpa.PersistenceProvider
 
         </provider>
 
         </provider>
        <properties>
 
    <!--Note that puABC must exist and be defined in the same jar file with this persistence.xml-->
 
    <property name="eclipselink.define.add-contained-pu.puABC" value=""/>
 
    <!--Note that puXYZ must exist and be defined in the same jar file with this persistence.xml-->
 
    <property name="eclipselink.define.add-contained-pu.puXYZ" value=""/>
 
        </properties>
 
    </persistence-unit>
 
</persistence>
 
</source>
 
The result is SessionBroker persistence unit named "broker" that aggregates two ServerSessions - one maps classes A, B, C; another - X, Y, Z.
 
  
<source lang="xml">
+
        <jar-file>member1.jar</jar-file>
<!--Scenario 2 - override some of the properies of puABC and puXYZ -->
+
        <jar-file>member2.jar</jar-file>
-<persistence 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 persistence_1_0.xsd" version="1.0">
+
 
    <!-- note that there is no need to pass transaction type down to contained sessions - that will be done automatically -->
+
    <persistence-unit name="broker" transaction-type="JPA">
+
        <provider>
+
            org.eclipse.persistence.jpa.PersistenceProvider
+
        </provider>
+
 
         <properties>
 
         <properties>
             <!-- note that there is no need to pass server platform down to contained sessions - that will be done automatically -->
+
             <property name="eclipselink.composite-unit" value="true"/>
 
             <property name="eclipselink.target-server" value="WebLogic_10"/>
 
             <property name="eclipselink.target-server" value="WebLogic_10"/>
 
    <!--Note that puABC must exist and be defined in the same jar file with this persistence.xml-->
 
    <property name="eclipselink.define.add-contained-pu.puABC" value=""/>
 
    <property name="javax.persistence.jtaDataSource.puABC" value="ElOracleJTA"/>
 
    <property name="javax.persistence.nonjtaDataSource.puABC" value="ElOracle"/>
 
            <!-- Switching to data sources from user/password - have to remove user name-->
 
    <property name="javax.persistence.jdbc.user.puABC" value=""/>
 
 
    <!--Note that puXYZ must exist and be defined in the same jar file with this persistence.xml-->
 
    <property name="eclipselink.define.add-contained-pu.puXYZ" value=""/>
 
    <property name="javax.persistence.jtaDataSource.puXYZ" value="ElMySQLJTA"/>
 
    <property name="javax.persistence.nonjtaDataSource.puXYZ" value="ElMySQL"/>
 
            <!-- Switching to data sources from user/password - have to remove user name-->
 
    <property name="javax.persistence.jdbc.user.puXYZ" value=""/>
 
 
         </properties>
 
         </properties>
 
     </persistence-unit>
 
     </persistence-unit>
Line 206: Line 262:
 
</source>
 
</source>
  
The result is SessionBroker persistence unit named "broker" that aggregates two ServerSessions - one maps classes A, B, C; another - X, Y, Z.
+
* memberPu1 defined in member1.jar file. It could be used independently as well as inside composite persistence unit.
The original connection parameters in both member sessions were substituted with the ones provided in SessionBroker properties.
+
 
+
** Split single persistent unit.
+
There is a single predefined persistence unit:  puABCXYZ (that maps classes A, B, C, X, Y, Z).
+
There could be any sorts of references between the classes.
+
Below is example that contains persistence.xml of the original persistence unit and for SessionBroker persistence unit.
+
 
<source lang="xml">
 
<source lang="xml">
<!--Original persistence unit -->
+
<persistence 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 persistence_1_0.xsd" version="1.0">
-<persistence 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 persistence_1_0.xsd" version="1.0">
+
     <persistence-unit name="memberPu1" transaction-type="JTA">
     <persistence-unit name="puABCXYZ" transaction-type="RESOURCE_LOCAL">
+
 
         <provider>
 
         <provider>
 
             org.eclipse.persistence.jpa.PersistenceProvider
 
             org.eclipse.persistence.jpa.PersistenceProvider
 
         </provider>
 
         </provider>
 +
        <mapping-file>META-INF/advanced-entity-mappings1.xml</mapping-file>
 +
        <jta-data-source>jdbc/OracleJtaDS</jta-data-source>
 
         <exclude-unlisted-classes>false</exclude-unlisted-classes>
 
         <exclude-unlisted-classes>false</exclude-unlisted-classes>
 
         <properties>
 
         <properties>
    <property name="javax.persistence.jdbc.user" value="MyUser"/>
+
            <property name="eclipselink.target-server" value="WebLogic_10"/>
    <property name="javax.persistence.jdbc.password" value="MyPassword"/>
+
             <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.oracle.Oracle11Platform"/>
             <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
+
            <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@qaott11.ca.oracle.com:1521:toplink"/>
+
 
         </properties>
 
         </properties>
 
     </persistence-unit>
 
     </persistence-unit>
Line 231: Line 280:
 
</source>
 
</source>
  
 +
* memberPu2 defined in member2.jar file. It has dependency on a class defined in member1.jar and can't be used independently.
 
<source lang="xml">
 
<source lang="xml">
<!--SessionBroker persistence unit -->
+
<persistence 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 persistence_1_0.xsd" version="1.0">
-<persistence 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 persistence_1_0.xsd" version="1.0">
+
     <persistence-unit name="memberPu2">
     <persistence-unit name="puABCXYZ" transaction-type="RESOURCE_LOCAL">
+
 
         <provider>
 
         <provider>
 
             org.eclipse.persistence.jpa.PersistenceProvider
 
             org.eclipse.persistence.jpa.PersistenceProvider
 
         </provider>
 
         </provider>
 +
        <mapping-file>META-INF/advanced-entity-mappings2.xml</mapping-file>
 +
        <jta-data-source>jdbc/MySqlJtaDS</jta-data-source>
 
         <exclude-unlisted-classes>false</exclude-unlisted-classes>
 
         <exclude-unlisted-classes>false</exclude-unlisted-classes>
 
         <properties>
 
         <properties>
    <property name="javax.persistence.jdbc.user" value="MyUser"/>
+
             <property name="eclipselink.composite-unit.member" value="true"/>
    <property name="javax.persistence.jdbc.password" value="MyPassword"/>
+
             <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.MySQLPlatform"/>
             <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
+
            <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@qaott11.ca.oracle.com:1521:toplink"/>
+
 
+
    <!--Note that puXYZ does not exist - it's used as an alias for the new ServerSession to be created-->
+
            <!--either provide full class name-->
+
    <property name="eclipselink.split-contained-pu.package.X" value="puXYZ"/>
+
    <property name="eclipselink.split-contained-pu.package.Y" value="puXYZ"/>
+
             <!--or entity name-->
+
    <property name="eclipselink.split-contained-pu.Z" value="puXYZ"/>
+
    <property name="javax.persistence.jdbc.user.puXYZ" value="MyUser2"/>
+
    <property name="javax.persistence.jdbc.password.puXYZ" value="MyPassword2"/>
+
            <property name="javax.persistence.jdbc.driver.puXYZ" value="com.mysql.jdbc.Driver"/>
+
            <property name="javax.persistence.jdbc.url.puXYZ" value="jdbc:mysql://qaott51.ca.oracle.com:3306/MyUser2"/>
+
 
         </properties>
 
         </properties>
 
     </persistence-unit>
 
     </persistence-unit>
Line 260: Line 298:
 
</source>
 
</source>
  
The result is SessionBroker persistence unit that aggregates two ServerSessions - one maps classes A, B, C; another - X, Y, Z.
+
All three jars - composite and the two members - should be deployed on the same class loader.
The ServerSession that maps classes X, Y, Z is created using all the properties defined in the persistence unit, overriding with the values designated to puXYZ.
+
In case of application server the jars should by packed in an ear file; in standalone case put on the class pass.
For all the remaining classes (in this case A, B, C) the ServerSession is created with all the original properties.
+
As usual compositePu could be accessed either through injection (in app. server case):
 
+
<source lang="java">
* Mix the two main use cases.
+
@PersistenceUnit(unitName="compositePu")
Let's create a SessionBroker persistence unit from original puABC, by splitting class C and adding puXYZ.
+
EntityManagerFactory entityManagerFactory;
Below is example that contains persistence.xml of the original persistence unit and for SessionBroker persistence unit.
+
@PersistenceUnit(unitName="compositePu")
<source lang="xml">
+
EntityManager entityManager;
<!--Original persistence unit -->
+
</source>
-<persistence 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 persistence_1_0.xsd" version="1.0">
+
or using Persistence:
    <persistence-unit name="puABC" transaction-type="RESOURCE_LOCAL">
+
<source lang="java">
        <provider>
+
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("compositePu", properties);
            org.eclipse.persistence.jpa.PersistenceProvider
+
        </provider>
+
        <class>A</class>
+
        <class>B</class>
+
        <class>C</class>
+
        <properties>
+
    <property name="javax.persistence.jdbc.user" value="MyUser"/>
+
    <property name="javax.persistence.jdbc.password" value="MyPassword"/>
+
            <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
+
            <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@qaott11.ca.oracle.com:1521:toplink"/>
+
        </properties>
+
    </persistence-unit>
+
</persistence>
+
 
</source>
 
</source>
  
<source lang="xml">
+
== Persistence Unit Properties ==
<!--SessionBroker persistence unit -->
+
* Composite Persistence Unit property could be specified either in its persistence.xml or passed to createEntityManagerFactory method;
-<persistence 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 persistence_1_0.xsd" version="1.0">
+
* Composite member Persistence Unit property could be either specified in its persistence.xml or passed to composite's createEntityManagerFactory through "eclipselink.composite.properties" property.
    <persistence-unit name="puABCXYZ" transaction-type="RESOURCE_LOCAL">
+
{|{{BMTableStyle}}
        <provider>
+
|-{{BMTHStyle}}
            org.eclipse.persistence.jpa.PersistenceProvider
+
| PersistenceUnitProperties.
        </provider>
+
| property name
        <class>A</class>
+
| composite pu
        <class>B</class>
+
| composite member pu
        <class>C</class>
+
| comment
        <properties>
+
|-
    <property name="javax.persistence.jdbc.user" value="MyUser"/>
+
| COMPOSITE_UNIT
    <property name="javax.persistence.jdbc.password" value="MyPassword"/>
+
| eclipselink.composite-unit
            <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
+
| processed
            <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@qaott11.ca.oracle.com:1521:toplink"/>
+
| advanced
 +
| if specified by member then the member is substituted for its own members
 +
|-  
 +
| COMPOSITE_UNIT_MEMBER
 +
| eclipselink.composite-unit.member
 +
| advanced
 +
| processed
 +
| if specified by composite then the composite must be member of another composite
 +
|-  
 +
| COMPOSITE_PROPERTIES
 +
| eclipselink.composite.properties
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| TRANSACTION_TYPE
 +
| javax.persistence.transactionType
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| TARGET_SERVER
 +
| eclipselink.target-server
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| LOGGING_*
 +
| eclipselink.logging.*
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| PROFILER
 +
| eclipselink.profiler
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| COORDINATION_*
 +
| eclipselink.cache.coordination.*
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| SESSION_NAME
 +
| eclipselink.session-name
 +
| processed
 +
| advanced
 +
| member session name is used to read the session from sessions.xml, but the deployed session always has the same name as the member persistence unit (as it's defined in memberPuInfo.getPersistenceUnitName())
 +
|-
 +
| DEPLOY_ON_STARTUP
 +
| eclipselink.deploy-on-startup
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| VALIDATION_ONLY_PROPERTY
 +
| eclipselink.validation-only
 +
| processed
 +
| ''processed''
 +
| {{bug|348815}}: WRONG BEHAVIOUR in 2.3, should be processed by composite only, ignored by member persistence unit. Workaround for now: specify the property in the composite and in all its members. THAT HAS BEEN FIXED in 2.3.1.
 +
|-  
 +
| VALIDATION_*
 +
| eclipselink.validation.*
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| CLASSLOADER
 +
| eclipselink.classloader
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| THROW_EXCEPTIONS
 +
| eclipselink.orm.throw.exceptions
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| FLUSH_CLEAR_CACHE
 +
| eclipselink.flush-clear.cache
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| VALIDATE_EXISTENCE
 +
| eclipselink.validate-existence
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| JOIN_EXISTING_TRANSACTION
 +
| eclipselink.transaction.join-existing
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| PERSISTENCE_CONTEXT_*
 +
| eclipselink.persistence-context.*
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| ALLOW_ZERO_ID
 +
| eclipselink.allow-zero-id
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| SESSION_CUSTOMIZER
 +
| eclipselink.session.customizer
 +
| processed
 +
| processed
 +
| Members' customizers processed before composite customizer.
 +
|-
 +
| SESSIONS_XML
 +
| eclipselink.sessions-xml
 +
| exception
 +
| processed
 +
| Composite can't be read from sessions.xml - exception will be thrown. Note that a non-composite persistence unit should be able to use a SessionBroker defined in sessions.xml (not tested, but should work).
 +
|-
 +
| JTA_DATASOURCE
 +
| javax.persistence.jtaDataSource
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| NON_JTA_DATASOURCE
 +
| javax.persistence.nonJtaDataSource
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| NATIVE_SQL
 +
| eclipselink.jdbc.native-sql
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| SQL_CAST
 +
| eclipselink.jdbc.sql-cast
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| JDBC_*
 +
| javax.persistence.jdbc.* eclipselink.jdbc.*
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| CONNECTION_POOL_*
 +
|
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| PARTITIONING.*
 +
| eclipselink.partitioning.*
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| EXCLUSIVE_CONNECTION_*
 +
| eclipselink.jdbc.exclusive-connection.*
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| CACHE.*
 +
| eclipselink.cache.*
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| TARGET_DATABASE
 +
| eclipselink.target-database
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| TABLE_CREATION_SUFFIX
 +
| eclipselink.ddl-generation.table-creation-suffix
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| EXCLUDE_ECLIPSELINK_ORM_FILE
 +
| eclipselink.exclude-eclipselink-orm
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| WEAVING
 +
| eclipselink.weaving
 +
| processed
 +
| ignored
 +
| Composite switches weaving on and off for all members.
 +
|-
 +
| WEAVING_*
 +
| eclipselink.weaving.*
 +
| ignored
 +
| processed
 +
| If the weaving is on then members use their own weaving properties.
 +
|-
 +
| DESCRIPTOR_CUSTOMIZER_*
 +
| eclipselink.descriptor.customizer.*
 +
| ignored
 +
| processed
 +
| TODO? Should we follow the same pattern as SessionCustomizer and process composite's DescriptorCustomizers after members' ones?
 +
|-
 +
| NATIVE_QUERY_UPPERCASE_COLUMNS
 +
| eclipselink.jdbc.uppercase-columns
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| UPPERCASE_COLUMN_NAMES
 +
| eclipselink.jpa.uppercase-column-names
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| BATCH_WRITING.*
 +
| eclipselink.jdbc.batch-writing.*
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| SESSION_EVENT_LISTENER_CLASS
 +
| eclipselink.session-event-listener
 +
| processed
 +
| processed
 +
| EventListener defined by a composite member won't receive evens risen by a UnitOfWork - only events risen by it's member. Also see {{bug|348759}}. EventListener specified by composite will receive all event (risen by either unit of work or members).
 +
|-
 +
| EXCEPTION_HANDLER_CLASS
 +
| eclipselink.exception-handler
 +
| processed
 +
| processed
 +
| First ExceptionHandler specified by member handles exception. If it is not specified or fails then composite's ExceptionHandler handles the original exception.
 +
|-
 +
| INCLUDE_DESCRIPTOR_QUERIES
 +
| eclipselink.session.include.descriptor.queries
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| ID_VALIDATION
 +
| eclipselink.id-validation
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| TEMPORAL_MUTABLE
 +
| eclipselink.temporal.mutable
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| ORM_SCHEMA_VALIDATION
 +
| eclipselink.orm.validate.schema
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| DDL_*
 +
|
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| PESSIMISTIC_LOCK_TIMEOUT
 +
| javax.persistence.lock.timeout
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| QUERY_TIMEOUT
 +
| javax.persistence.query.timeout
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| ORACLE_PROXY_TYPE
 +
| eclipselink.oracle.proxy-type
 +
| ignored
 +
| processed
 +
|
 +
|}
  
    <!--Note that puC does not exist - it's used as an alias for the new ServerSession to be created-->
+
== Entity Manager Properties ==
            <!--either provide full class name or entity name-->
+
* Composite Entity Manager property could be directly passed to createEntityManager method or setProperty method
    <property name="eclipselink.split-contained-pu.C" value="puC"/>
+
* Composite member property could be passed to the same methods through "eclipselink.composite.properties" property.
    <property name="javax.persistence.jdbc.user.puC" value="MyUser2"/>
+
{|{{BMTableStyle}}
    <property name="javax.persistence.jdbc.password.puC" value="MyPassword2"/>
+
|-{{BMTHStyle}}
            <property name="javax.persistence.jdbc.driver.puC" value="com.mysql.jdbc.Driver"/>
+
| EntityManagerProperties.
            <property name="javax.persistence.jdbc.url.puC" value="jdbc:mysql://qaott51.ca.oracle.com:3306/MyUser2"/>
+
| property name
 +
| composite pu
 +
| composite member pu
 +
| comment
 +
|-  
 +
| COMPOSITE_PROPERTIES
 +
| eclipselink.composite.properties
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| FLUSH_CLEAR_CACHE
 +
| eclipselink.flush-clear.cache
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| VALIDATE_EXISTENCE
 +
| eclipselink.validate-existence
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| JOIN_EXISTING_TRANSACTION
 +
| eclipselink.transaction.join-existing
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| PERSISTENCE_CONTEXT_*
 +
| eclipselink.persistence-context.*
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| ORDER_UPDATES
 +
| eclipselink.order-updates
 +
| processed
 +
| ignored
 +
|
 +
|-
 +
| EXCLUSIVE_CONNECTION_*
 +
| eclipselink.jdbc.exclusive-connection.*
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| JDBC_DRIVER
 +
| javax.persistence.jdbc.driver
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| JDBC_URL
 +
| javax.persistence.jdbc.url
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| JDBC_USER
 +
| javax.persistence.jdbc.user
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| JDBC_PASSWORD
 +
| javax.persistence.jdbc.password
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| JTA_DATASOURCE
 +
| javax.persistence.jtaDataSource
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| NON_JTA_DATASOURCE
 +
| javax.persistence.nonJtaDataSource
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| CONNECTION_POLICY
 +
| eclipselink.jdbc.connection-policy
 +
| ignored
 +
| processed
 +
|
 +
|-
 +
| ORACLE_PROXY_TYPE
 +
| eclipselink.oracle.proxy-type
 +
| ignored
 +
| processed
 +
|
 +
|}
  
    <!--Note that puXYZ must exist and be defined in the same jar file with this persistence.xml-->
+
== Limitations ==
    <property name="eclipselink.define.add-contained-pu.puXYZ" value=""/>
+
* Main limitations' cause is that tables in different data bases cannot be joined in a query. Examples:
         </properties>
+
** Entities mapped in different composite members could not be joined in a query.
     </persistence-unit>
+
** If deletion of an entity causes deletion from a table that is mapped by another composite member then delete all query can't be performed.
</persistence>
+
*** Therefore delete all cannot be used if an entity
 +
**** has ElementCollection mapped in another composite member,
 +
**** owns bidirectional relationship with a JoinTable with target mapped in another composite member,
 +
**** has any reference mapping that is privately owned with target mapped in another composite member.
 +
* Inheritance hierarchy cannot be shared between different composite members.
 +
* If target of a reference mapping is defined in a different composite member and JoinTable is used, then the join table must belong to the target composite member.
 +
** Such mappings must be unidirectional - the "invert" mapping cannot use "mappedBy".
 +
*** That's because JoinTable must be defined in the same composite member with target entity: master mapping requires it to be in slave's member, slave mapping - in master's.
 +
** Workaround is to define independent invert mapping with its own JoinTable.
 +
*** If user maintains both sides of the relationship then the two join tables will be in sync.
 +
* Native query created without result class must specify the target composite member persistence unit.
 +
<source lang=java>
 +
em.createNativeQuery("SELECT F_NAME FROM MBR2_EMPLOYEE").setHint(QueryHints.COMPOSITE_UNIT_MEMBER, "composite-advanced-member_2").getResultList();
 +
</source>
 +
 
 +
== Extensions ==
 +
* User can specify ElementCollection with primitive type target values with CollectionTable defined in a different composite member persistence unit using
 +
** Annotations
 +
<source lang=java>
 +
@ElementCollection()
 +
@CollectionTable(name = "MBR1_RESPONS", joinColumns=@JoinColumn(name="EMP_ID"))
 +
@CompositeMember("composite-advanced-member_1")
 +
@Column(name = "DESCRIPTION")
 +
public Collection<String> getResponsibilities() {
 +
    return responsibilities;
 +
}
 +
</source>
 +
** eclipselink-orm.xml
 +
<source lang=xml>
 +
<element-collection name="responsibilities" composite-member="xml-composite-advanced-member_3">
 +
    <column name="DESCRIPTION"/>
 +
    <collection-table name="XML_MBR3_RESPONS">
 +
         <join-column name="EMP_ID"/>
 +
     </collection-table>
 +
</element-collection>
 
</source>
 
</source>
The result is SessionBroker persistence unit that aggregates three ServerSessions - one maps classes A, B; another -  C; yet another - X, Y, Z.
+
** No @CompositeMember annotation (or composite-member attribute) is required if CollectionTable is defined in the same composite member persistence unit as the source.
The ServerSession that maps classes X, Y, Z is created using puXYZ.
+
The ServerSession that maps class C is created using all the properties defined in the persistence unit, overriding with the values designated to puC.
+
For all the remaining classes (in this case A and B) the ServerSession is created with all the original properties.
+
  
 
== Documentation ==
 
== Documentation ==
Line 334: Line 774:
 
|-  
 
|-  
 
| 1
 
| 1
| Should this feature include both split and aggregated persistence units?
+
| Should this feature include both split and aggregated persistence units? NO split support.
 
|-  
 
|-  
 
| 2
 
| 2
| In the case of split persistence units where should the additional data sources be defined? PU properties in persistence.xml, eclipselink-orm.xml, both? Since it is possible for different data sources to be different database vendors or versions it should be possible to configure all JDBC/connection/pool level options on each data source.
+
| In the case of split persistence units where should the additional '''Data Source'''s be defined? PU properties in persistence.xml, eclipselink-orm.xml, both? Since it is possible for different '''Data Source'''s to be different database vendors or versions it should be possible to configure all JDBC/connection/pool level options on each data source. NO split support.
 
|-  
 
|-  
 
| 3
 
| 3
| Should this feature include support to customize additional datasources with persistence unit properties.
+
| Should this feature include support to customize additional '''Data Source'''s with persistence unit properties. NO split support.
 
|-  
 
|-  
 
| 4
 
| 4
| In the case of aggregate persistence units, should persistence units be usable on their own.
+
| In the case of aggregate persistence units, should persistence units be usable on their own. YES, if independent.
 
|}
 
|}
  
Line 361: Line 801:
 
|}
 
|}
  
== Future Considerations ==
+
== Known problems in 2.3 ==
 
+
* {{bug|348759}} - SessionBroker's member sessions get postLogin event before descriptors initialized - Fixed in 2.3.1
During the research for this project the following items were identified as out of scope but are captured here as potential future enhancements. If agreed upon during the review process these should be logged in the bug system.
+
* {{bug|348815}} - Composite persistence unit does not process VALIDATION_ONLY_PROPERTY correctly - Fixed in 2.3.1
 
+
1. It looks like this project is only considering of enabling the existing session broker support via JPA; i.e. enable the application to maintain different tables in different database instances. The concept overview or the requirements does not give any hint of enabling the application to define strategies for saving different sets of data in different database instances so that each databse instance contains the complete data matching a particular criteria. These days the more commonly practised database partitioning method is the latter one, popularly called sharding.
+
 
+
It would be better to consider providing support for this feature too since an attempt is being made to overhaul the sessionbroker support in eclipselink. In this method, every entity belongs to all the persistence units, however, eclipselink has to consult the defined criteria (range based or list based) while saving or retrieving the entities from any of the configured database instances.one of the complexities that may need to be addressed is how to handle the changes when a new databse instance is added to participate in the partitioning, especially if there needs to be a reorderig of the data across the database instances becasue the newly added instance falls in an intermediate range.
+

Latest revision as of 18:24, 13 July 2011

Design Specification: Persistence Unit Composition

This feature adds support for persistence units being composed. This means a user can define multiple persistence units with a unique set of entity types and expose them through a composite persistence unit which combines the set of classes across multiple data sources to expose a single persistence context.

ER 328404

Document History

old version of the doc

Date committer description
2011/04/06 Andrei Ilitchev Initial New Version

Project overview

The goal is to combine several persistence units into a single one.

em.persist(new A(..));
em.persist(new Z(..));
// insert A into db1; insert Z into db2:
// the two different data bases possibly from different vendors
em.flush();

Concepts

Terminology

  • Data Source: For the purposes of this discussion a data-source will include JTA and non-JTA data sources as well as EclipseLink's native JDBC connection pools.
  • Composite PU: Refers to a PU which combines 2 or more Composite Member PUs to provide a persistence context which allows queries and transactions (with limitations) across the combined set of entity types.

Requirements

# Description
1 Add support for a single persistence context accessing entities stored in different Data Sources (schemas/table-space/database) where application developers can perform queries and transactions across the complete set of entities transparently.
2 Support mapping relationships between entities in different Data Sources.
3 Provide easy to use JPA configuration.
4 Clearly capture usage limitations and exceptions expected in Java Docs and user documentation. The most basic example of this is the ability to join across tables in different Data Sources. This limitation effects mapping and query execution and optimizations. These issues need to be identified and documented.
5 Support container managed and application bootstrap JPA usage with dynamic, static, and no weaving.

User Bugs

The following potentially related bugs should be taken into consideration in this feature work.

  • JPA enhancement requests.
    • bug 260258 - Add JPA EntityManagerFactoryBroker support
  • Core bugs
    • bug 269213 - SessionBroker handling of ExceptionHandler broken because stale copy/paste
    • bug 281569 - Integration of JPA using transaction-type="JTA" but without EJB container, set-up incomplete commit cleanup
    • bug 326649 - DatabaseSessionImpl.finalize() leads to ClassCastException
    • bug 329185 - SessionBroker: ClassCastException in Cursor.buildAndRegisterObject between ServerSession and UnitOfWorkImpl
    • bug 332581 - SessionBroker session event issues to consider and resolve when implementing JPA Session Broker
    • bug 331712 - Allow Isolated classes to work with client session broker

Design Constraints

Design / Functionality

Testing

  • The tests are (as always) in trunk\jpa\eclipselink.jpa.test, they are added to FullRegressionTestSuite.
  • New test models were defined that mirror some existing test models.
  • Each of the new models was divided into three composite members.
    • Division was done in such a way that there are lots of references between classes that belong to different composite members.
  • For each new model a new test suite was created that mirrors existing test suite.
  • It might be useful to compare the sources of the original and composite versions of mapped classes and tests to see composite specifics and limitations.
  • By default all three composite member persistence unit in each model will use the same data base (specified by db.* properties in test.properties file or passed to TestBrowser)
    • To test with three different databases, in test.properties file specify
      • either single.db=false - that would cause member_2 and member_3 to use connection parameters specified in their persistence.xml files;
      • or db2.* and db3.* properties (following the pattern of db.* properties).
      • member_1 always uses the main data base (specified by db.* properties in test.properties file or passed to TestBrowser).

Annotations

  • Original
    • Source (src)
      • org.eclipse.persistence.testing.models.jpa.advanced.*
      • org.eclipse.persistence.testing.tests.jpa.advanced.EntityManagerJUnitTestSuite
    • Persistence Unit "default"
      • Resource
        • eclipselink-annotation-model
      • Model jar file
        • eclipselink-annotation-model.jar
  • Composite
    • Source (src)
      • org.eclipse.persistence.testing.models.jpa.composite.advanced.*
      • org.eclipse.persistence.testing.models.jpa.composite.advanced.member_1.*
      • org.eclipse.persistence.testing.models.jpa.composite.advanced.member_2.*
      • org.eclipse.persistence.testing.models.jpa.composite.advanced.member_3.*
      • org.eclipse.persistence.testing.tests.jpa.composite.advanced.EntityManagerJUnitTestSuite
    • Persistence Unit "composite-advanced"
      • Resource
        • eclipselink-composite-advanced-model
        • eclipselink-composite-advanced-model-member_1
        • eclipselink-composite-advanced-model-member_2
        • eclipselink-composite-advanced-model-member_3
      • Model jar file
        • eclipselink-composite-advanced-model.jar
      • Member jar files
        • eclipselink-composite-advanced-model-member_1.jar
        • eclipselink-composite-advanced-model-member_2.jar
        • eclipselink-composite-advanced-model-member_3.jar
    • Members' database objects' (tables and sequences) names
      • prefixed with "MBR1_", "MBR2_", "MBR3_" respectively.

XML

  • Original
    • Source (src)
      • org.eclipse.persistence.testing.models.jpa.xml.advanced
      • org.eclipse.persistence.testing.tests.jpa.xml.advanced.EntityMappingsAdvancedJUnitTestCase
        • to run it with pu "extended-advanced" (uses eclipselink-orm.xml) use -Dorm.testing=eclipselink
    • Persistence Unit "default"
      • Resource
        • eclipselink-xml-only-model
      • Model jar file
        • eclipselink-annotation-model.jar
    • Persistence Unit "extended-advanced" (uses eclipselink-orm.xml)
      • Resource
        • eclipselinkorm\eclipselink-xml-extended-model
      • Model jar file
        • eclipselink-xml-extended-model.jar
  • Composite
    • Source (src)
      • org.eclipse.persistence.testing.models.jpa.xml.composite.advanced.*
      • org.eclipse.persistence.testing.models.jpa.xml.composite.advanced.member_1.*
      • org.eclipse.persistence.testing.models.jpa.xml.composite.advanced.member_2.*
      • org.eclipse.persistence.testing.models.jpa.xml.composite.advanced.member_3.*
      • org.eclipse.persistence.testing.tests.jpa.composite.xml.composite.advanced.EntityMappingsAdvancedJUnitTestCase
        • to run it with pu "xml-extended-composite-advanced" (uses eclipselink-orm.xml) use -Dorm.testing=eclipselink
    • Persistence Unit "xml-composite-advanced"
      • Resource
        • eclipselink-xml-composite-advanced-model
        • eclipselink-xml-composite-advanced-model-member_1
        • eclipselink-xml-composite-advanced-model-member_2
        • eclipselink-xml-composite-advanced-model-member_3
      • Model jar file
        • eclipselink-xml-composite-advanced-model.jar
      • Member jar files
        • eclipselink-xml-composite-advanced-model-member_1.jar
        • eclipselink-xml-composite-advanced-model-member_2.jar
        • eclipselink-xml-composite-advanced-model-member_3.jar
    • Persistence Unit "xml-extended-composite-advanced"
      • Resource
        • eclipselinkorm\eclipselink-xml-extended-composite-advanced-model
        • eclipselinkorm\eclipselink-xml-extended-composite-advanced-model-member_1
        • eclipselinkorm\eclipselink-xml-extended-composite-advanced-model-member_2
        • eclipselinkorm\eclipselink-xml-extended-composite-advanced-model-member_3
      • Model jar file
        • eclipselink-xml-extended-composite-advanced-model.jar
      • Member jar files
        • eclipselink-xml-extended-composite-advanced-model-member_1.jar
        • eclipselink-xml-extended-composite-advanced-model-member_2.jar
        • eclipselink-xml-extended-composite-advanced-model-member_3.jar
    • Members' database objects' (tables and sequences) names
      • prefixed with "XML_MBR1_", "XML_MBR2_", "XML_MBR3_" respectively.

API

Tooling

The Dali team should be made aware of this feature work and track an enhancement request to uptake it.

Config files

  • Composite PU must be configured in persistence.xml using property:
/**
* Indicates if it's a composite persistence unit ("true").
* The property must be specified in persistence.xml of a composite persistence unit.
* The property passed to createEntityManagerFactory method or in system properties is ignored.
* Composite persistence unit would contain all persistence units found in jar files specified by <jar-file> elements in persistence.xml. 
*    <jar-file>member1.jar</jar-file>
*    <jar-file>member2.jar</jar-file>
*    <properties>
*        <property name="eclipselink.composite-unit" value="true"/>
*    </properties>
* @see #COMPOSITE_UNIT_MEMBER
* @see #COMPOSITE_UNIT_PROPERTIES
*/
public static final String COMPOSITE_UNIT = "eclipselink.composite-unit";
  • Composite Member PU may specify in persistence.xml that it can't be used as an independent persistence unit:
/**
* Indicates if the persistence unit must be a member of a composite persistence unit ("true"),
* can't be used as an independent persistence unit.
* That happens if persistence unit has dependencies on other persistence unit(s).
* The property may be specified in persistence.xml.
* The property passed to createEntityManagerFactory method or in system properties is ignored.
* If this property is set to true, EntityManagerFactory still could be created,
* but it can't be connected: an attempt to create entity manager would cause an exception.
* @see #COMPOSITE_UNIT
* @see #COMPOSITE_UNIT_PROPERTIES
*/
public static final String COMPOSITE_UNIT_MEMBER = "eclipselink.composite-unit.member";
  • While creating Composite PU EntityManagerFactory properties could be passed to Composite Member PUs:
/**
* The property may be passed to createEntityManagerFactory method of a composite persistence unit
* to pass properties to member persistence units.
* The value is a map: 
* the key is a member persistence unit's name,
* the value is a map of properties to be passed to this persistence unit. 
* "eclipselink.composite-unit.properties" -> (
*   ("memberPu1" -> (   "javax.persistence.jdbc.user" -> "user1", 
*                          "javax.persistence.jdbc.password" -> "password1",
*                          "javax.persistence.jdbc.driver" -> "oracle.jdbc.OracleDriver",
*                          "javax.persistence.jdbc.url" -> "jdbc:oracle:thin:@oracle_db_url:1521:db",
*                    ) , 
*   ("memberPu2" -> (   "javax.persistence.jdbc.user" -> "user2",
*                          "javax.persistence.jdbc.password" -> "password2"
*                          "javax.persistence.jdbc.driver" -> "com.mysql.jdbc.Driver",
*                          "javax.persistence.jdbc.url" -> "jdbc:mysql://my_sql_db_url:3306/user2",
*                    )
* )
* @see #COMPOSITE_UNIT
*/
public static final String COMPOSITE_UNIT_PROPERTIES = "eclipselink.composite-unit.properties";
  • Transaction type should be specified in composite persistence unit (transaction types of composite members ignored).
  • Data sources should be specified in composite member persistence units (those specified in the composite are ignored).

Example

  • compositePu specifies transaction type and server platform. It will contain all persistence units defined in member1.jar and member2.jar files.
<persistence 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 persistence_1_0.xsd" version="1.0">
    <persistence-unit name="compositePu" transaction-type="JTA">
        <provider>
            org.eclipse.persistence.jpa.PersistenceProvider
        </provider>
 
        <jar-file>member1.jar</jar-file>
        <jar-file>member2.jar</jar-file>
 
        <properties>
            <property name="eclipselink.composite-unit" value="true"/>
            <property name="eclipselink.target-server" value="WebLogic_10"/>
        </properties>
    </persistence-unit>
</persistence>
  • memberPu1 defined in member1.jar file. It could be used independently as well as inside composite persistence unit.
<persistence 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 persistence_1_0.xsd" version="1.0">
    <persistence-unit name="memberPu1" transaction-type="JTA">
        <provider>
            org.eclipse.persistence.jpa.PersistenceProvider
        </provider>
        <mapping-file>META-INF/advanced-entity-mappings1.xml</mapping-file>
        <jta-data-source>jdbc/OracleJtaDS</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="eclipselink.target-server" value="WebLogic_10"/>
            <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.oracle.Oracle11Platform"/>
        </properties>
    </persistence-unit>
</persistence>
  • memberPu2 defined in member2.jar file. It has dependency on a class defined in member1.jar and can't be used independently.
<persistence 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 persistence_1_0.xsd" version="1.0">
    <persistence-unit name="memberPu2">
        <provider>
            org.eclipse.persistence.jpa.PersistenceProvider
        </provider>
        <mapping-file>META-INF/advanced-entity-mappings2.xml</mapping-file>
        <jta-data-source>jdbc/MySqlJtaDS</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="eclipselink.composite-unit.member" value="true"/>
            <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.MySQLPlatform"/>
        </properties>
    </persistence-unit>
</persistence>

All three jars - composite and the two members - should be deployed on the same class loader. In case of application server the jars should by packed in an ear file; in standalone case put on the class pass. As usual compositePu could be accessed either through injection (in app. server case):

@PersistenceUnit(unitName="compositePu")
EntityManagerFactory entityManagerFactory;
@PersistenceUnit(unitName="compositePu")
EntityManager entityManager;

or using Persistence:

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("compositePu", properties);

Persistence Unit Properties

  • Composite Persistence Unit property could be specified either in its persistence.xml or passed to createEntityManagerFactory method;
  • Composite member Persistence Unit property could be either specified in its persistence.xml or passed to composite's createEntityManagerFactory through "eclipselink.composite.properties" property.
PersistenceUnitProperties. property name composite pu composite member pu comment
COMPOSITE_UNIT eclipselink.composite-unit processed advanced if specified by member then the member is substituted for its own members
COMPOSITE_UNIT_MEMBER eclipselink.composite-unit.member advanced processed if specified by composite then the composite must be member of another composite
COMPOSITE_PROPERTIES eclipselink.composite.properties processed ignored
TRANSACTION_TYPE javax.persistence.transactionType processed ignored
TARGET_SERVER eclipselink.target-server processed ignored
LOGGING_* eclipselink.logging.* processed ignored
PROFILER eclipselink.profiler processed ignored
COORDINATION_* eclipselink.cache.coordination.* processed ignored
SESSION_NAME eclipselink.session-name processed advanced member session name is used to read the session from sessions.xml, but the deployed session always has the same name as the member persistence unit (as it's defined in memberPuInfo.getPersistenceUnitName())
DEPLOY_ON_STARTUP eclipselink.deploy-on-startup processed ignored
VALIDATION_ONLY_PROPERTY eclipselink.validation-only processed processed bug 348815: WRONG BEHAVIOUR in 2.3, should be processed by composite only, ignored by member persistence unit. Workaround for now: specify the property in the composite and in all its members. THAT HAS BEEN FIXED in 2.3.1.
VALIDATION_* eclipselink.validation.* processed ignored
CLASSLOADER eclipselink.classloader processed ignored
THROW_EXCEPTIONS eclipselink.orm.throw.exceptions processed ignored
FLUSH_CLEAR_CACHE eclipselink.flush-clear.cache processed ignored
VALIDATE_EXISTENCE eclipselink.validate-existence processed ignored
JOIN_EXISTING_TRANSACTION eclipselink.transaction.join-existing processed ignored
PERSISTENCE_CONTEXT_* eclipselink.persistence-context.* processed ignored
ALLOW_ZERO_ID eclipselink.allow-zero-id processed ignored
SESSION_CUSTOMIZER eclipselink.session.customizer processed processed Members' customizers processed before composite customizer.
SESSIONS_XML eclipselink.sessions-xml exception processed Composite can't be read from sessions.xml - exception will be thrown. Note that a non-composite persistence unit should be able to use a SessionBroker defined in sessions.xml (not tested, but should work).
JTA_DATASOURCE javax.persistence.jtaDataSource ignored processed
NON_JTA_DATASOURCE javax.persistence.nonJtaDataSource ignored processed
NATIVE_SQL eclipselink.jdbc.native-sql ignored processed
SQL_CAST eclipselink.jdbc.sql-cast ignored processed
JDBC_* javax.persistence.jdbc.* eclipselink.jdbc.* ignored processed
CONNECTION_POOL_* ignored processed
PARTITIONING.* eclipselink.partitioning.* ignored processed
EXCLUSIVE_CONNECTION_* eclipselink.jdbc.exclusive-connection.* ignored processed
CACHE.* eclipselink.cache.* ignored processed
TARGET_DATABASE eclipselink.target-database ignored processed
TABLE_CREATION_SUFFIX eclipselink.ddl-generation.table-creation-suffix ignored processed
EXCLUDE_ECLIPSELINK_ORM_FILE eclipselink.exclude-eclipselink-orm ignored processed
WEAVING eclipselink.weaving processed ignored Composite switches weaving on and off for all members.
WEAVING_* eclipselink.weaving.* ignored processed If the weaving is on then members use their own weaving properties.
DESCRIPTOR_CUSTOMIZER_* eclipselink.descriptor.customizer.* ignored processed TODO? Should we follow the same pattern as SessionCustomizer and process composite's DescriptorCustomizers after members' ones?
NATIVE_QUERY_UPPERCASE_COLUMNS eclipselink.jdbc.uppercase-columns ignored processed
UPPERCASE_COLUMN_NAMES eclipselink.jpa.uppercase-column-names ignored processed
BATCH_WRITING.* eclipselink.jdbc.batch-writing.* ignored processed
SESSION_EVENT_LISTENER_CLASS eclipselink.session-event-listener processed processed EventListener defined by a composite member won't receive evens risen by a UnitOfWork - only events risen by it's member. Also see bug 348759. EventListener specified by composite will receive all event (risen by either unit of work or members).
EXCEPTION_HANDLER_CLASS eclipselink.exception-handler processed processed First ExceptionHandler specified by member handles exception. If it is not specified or fails then composite's ExceptionHandler handles the original exception.
INCLUDE_DESCRIPTOR_QUERIES eclipselink.session.include.descriptor.queries ignored processed
ID_VALIDATION eclipselink.id-validation ignored processed
TEMPORAL_MUTABLE eclipselink.temporal.mutable ignored processed
ORM_SCHEMA_VALIDATION eclipselink.orm.validate.schema ignored processed
DDL_* ignored processed
PESSIMISTIC_LOCK_TIMEOUT javax.persistence.lock.timeout ignored processed
QUERY_TIMEOUT javax.persistence.query.timeout ignored processed
ORACLE_PROXY_TYPE eclipselink.oracle.proxy-type ignored processed

Entity Manager Properties

  • Composite Entity Manager property could be directly passed to createEntityManager method or setProperty method
  • Composite member property could be passed to the same methods through "eclipselink.composite.properties" property.
EntityManagerProperties. property name composite pu composite member pu comment
COMPOSITE_PROPERTIES eclipselink.composite.properties processed ignored
FLUSH_CLEAR_CACHE eclipselink.flush-clear.cache processed ignored
VALIDATE_EXISTENCE eclipselink.validate-existence processed ignored
JOIN_EXISTING_TRANSACTION eclipselink.transaction.join-existing processed ignored
PERSISTENCE_CONTEXT_* eclipselink.persistence-context.* processed ignored
ORDER_UPDATES eclipselink.order-updates processed ignored
EXCLUSIVE_CONNECTION_* eclipselink.jdbc.exclusive-connection.* ignored processed
JDBC_DRIVER javax.persistence.jdbc.driver ignored processed
JDBC_URL javax.persistence.jdbc.url ignored processed
JDBC_USER javax.persistence.jdbc.user ignored processed
JDBC_PASSWORD javax.persistence.jdbc.password ignored processed
JTA_DATASOURCE javax.persistence.jtaDataSource ignored processed
NON_JTA_DATASOURCE javax.persistence.nonJtaDataSource ignored processed
CONNECTION_POLICY eclipselink.jdbc.connection-policy ignored processed
ORACLE_PROXY_TYPE eclipselink.oracle.proxy-type ignored processed

Limitations

  • Main limitations' cause is that tables in different data bases cannot be joined in a query. Examples:
    • Entities mapped in different composite members could not be joined in a query.
    • If deletion of an entity causes deletion from a table that is mapped by another composite member then delete all query can't be performed.
      • Therefore delete all cannot be used if an entity
        • has ElementCollection mapped in another composite member,
        • owns bidirectional relationship with a JoinTable with target mapped in another composite member,
        • has any reference mapping that is privately owned with target mapped in another composite member.
  • Inheritance hierarchy cannot be shared between different composite members.
  • If target of a reference mapping is defined in a different composite member and JoinTable is used, then the join table must belong to the target composite member.
    • Such mappings must be unidirectional - the "invert" mapping cannot use "mappedBy".
      • That's because JoinTable must be defined in the same composite member with target entity: master mapping requires it to be in slave's member, slave mapping - in master's.
    • Workaround is to define independent invert mapping with its own JoinTable.
      • If user maintains both sides of the relationship then the two join tables will be in sync.
  • Native query created without result class must specify the target composite member persistence unit.
em.createNativeQuery("SELECT F_NAME FROM MBR2_EMPLOYEE").setHint(QueryHints.COMPOSITE_UNIT_MEMBER, "composite-advanced-member_2").getResultList();

Extensions

  • User can specify ElementCollection with primitive type target values with CollectionTable defined in a different composite member persistence unit using
    • Annotations
@ElementCollection()
@CollectionTable(name = "MBR1_RESPONS", joinColumns=@JoinColumn(name="EMP_ID"))
@CompositeMember("composite-advanced-member_1")
@Column(name = "DESCRIPTION")
public Collection<String> getResponsibilities() {
    return responsibilities;
}
    • eclipselink-orm.xml
<element-collection name="responsibilities" composite-member="xml-composite-advanced-member_3">
    <column name="DESCRIPTION"/>
    <collection-table name="XML_MBR3_RESPONS">
        <join-column name="EMP_ID"/>
    </collection-table>
</element-collection>
    • No @CompositeMember annotation (or composite-member attribute) is required if CollectionTable is defined in the same composite member persistence unit as the source.

Documentation

Open Issues

This section lists the open issues that are still pending that must be decided prior to fully implementing this project's requirements.

Issue # Description / Notes
1 Should this feature include both split and aggregated persistence units? NO split support.
2 In the case of split persistence units where should the additional Data Sources be defined? PU properties in persistence.xml, eclipselink-orm.xml, both? Since it is possible for different Data Sources to be different database vendors or versions it should be possible to configure all JDBC/connection/pool level options on each data source. NO split support.
3 Should this feature include support to customize additional Data Sources with persistence unit properties. NO split support.
4 In the case of aggregate persistence units, should persistence units be usable on their own. YES, if independent.

Decisions

This section lists decisions made. These are intended to document the resolution of open issues or constraints added to the project that are important.

Issue # Description / Notes Decision

Known problems in 2.3

  • bug 348759 - SessionBroker's member sessions get postLogin event before descriptors initialized - Fixed in 2.3.1
  • bug 348815 - Composite persistence unit does not process VALIDATION_ONLY_PROPERTY correctly - Fixed in 2.3.1

Back to the top