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/UserGuide/sandbox/gelernter/Extensible Domain Models"

m
m
 
(41 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{EclipseLink_UserGuide
+
{{EclipseLink_UserGuide  
 
|info=y
 
|info=y
 
|toc=n
 
|toc=n
Line 6: Line 6:
 
|api=y
 
|api=y
 
|apis=
 
|apis=
 +
* [http://www.eclipse.org/eclipselink/api/latest/org/eclipse/persistence/annotations/VirtualAccessMethods.html @VirtualAccessMethods]
 +
* [[http://www.eclipse.org/eclipselink/api/latest/org/eclipse/persistence/jpa/JpaEntityManagerFactory.html#refreshMetadata(java.util.Map) RefreshMetadata()]]
 
|examples=y
 
|examples=y
 
|example=
 
|example=
*[[EclipseLink/Examples/JPA/xxxx|xxxx]]
+
*[[EclipseLink/Examples/JPA/Extensibility|Extensible Entities]]
 
}}
 
}}
 +
===******SANDBOX VERSION******===
 +
 +
''This topic is currently under review.''
 +
 
=Extensible Entities=
 
=Extensible Entities=
  
‘’This feature is new in EclipseLink 2.3.’’
+
{{EclipseLink_NewIn
 +
|version=2.3}}
 +
<br><br>.
  
You can define and use extensible entities where mappings can be added without redeploying the persistence unit. The entity stores extended attributes in a map. Values from this map are mapped to the database using an <tt>eclipselink-orm.xml</tt> mapping file. These extended mappings are ‘’’’’always?’’’’’ stored and managed externally, which allows you to define new mappings while the application is running.
+
Use the <tt>@VirtualAccessMethods</tt> annotation to specify that an entity is extensible. By using virtual properties in an extensible entity, you can specify mappings external to the entity. This allows you to modify the mappings without modifying the entity source file and without redeploying the entity's persistence unit.  
  
==Flex Columns Extension ==
+
Extensible entities are useful in a multi-tenant (or Software-as-a-Service) environment where a shared, generic application can be used by multiple clients (tenants). Tenants have private access to their own data, as well as to data shared with other tenants. See also [[EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Single-Table_Multi-Tenancy |Single-Table Multi-Tenancy]].
  
Entities can be extended using flexible columns. You can use such extended entities to do the following:
+
Using extensible entities, you can:
  
 
* Build an application where some mappings are common to all users and some mappings are user-specific.
 
* Build an application where some mappings are common to all users and some mappings are user-specific.
 
* Add mappings to an application after it is made available to a customer (even post-deployment).
 
* Add mappings to an application after it is made available to a customer (even post-deployment).
* Use the same EntityManagerFactory to work with data after mappings have changed  
+
* Use the same <tt>EntityManagerFactory</tt> to work with data after mappings have changed.
 
* Provide an additional source of metadata to be used by an application.  
 
* Provide an additional source of metadata to be used by an application.  
  
This feature is useful in a Software-as-a-Service (SaaS) environment where a shared, generic application can be customized by users to make use of data that is particular to their domain.
+
To create and support an extensible entity,  
  
To extend the entities and take advantage of flexible columns, you must do the following:
+
#Configure the entity. See [[#Configuring the Entity| Configuring the Entity]].
* Annotate entities to allow flexible mappings.
+
# Include flexible columns in the database table to store the additional data. See [[#Designing the Schema| Designing the Schema]].
* Provide facilities to store the additional data.
+
# Specify extended mappings in the <tt>eclipselink-orm.xml</tt> file. See [[#Providing Additional Mappings| Providing Additional Mappings]]
*’’’’’ more’’’’’
+
# Configure persistence.xml. See [[#Configuring persistence.xml|Configuring persistence.xml]].
 +
 
 +
===Configuring the Entity===
 +
To configure the entity,
 +
 
 +
# [[#Annotate with @VirtualAccessMethods| Annotate with <tt>@VirtualAccessMethods</tt>]]
 +
#  [[#Add get() and set() Methods| Add <tt>get()</tt> and <tt>set()</tt> methods]]
 +
# [[#Add a Data Structure|Add a data structure]]
 +
 
 +
====Annotate with @VirtualAccessMethods====
 +
 
 +
Annotate the entity with <tt>@VirtualAccessMethods</tt> to specify that it is extensible and to define virtual properties.  
 +
{{EclipseLink_AttributeTable
 +
|caption=@VirtualAccessMethods Attributes
 +
|content=
 +
<tr>
 +
<td><tt>get</tt></td>
 +
<td> The name of the getter method to use for the virtual property This method must take a single <tt>java.lang.String</tt> parameter and return a <tt>java.lang.Object</tt>. </td>
 +
<td><tt>get</tt></td>
 +
<td>Yes</td>
 +
</tr>
 +
<tr>
 +
<td>'''<tt>set</tt>'''</td>
 +
<td>The name of the setter method to use for the virtual property This method must take a <tt>java.lang.String</tt> parameter and return a <tt>java.lang.Object</tt> parameter.</td>
 +
<td><tt>set</tt></td>
 +
<td>Yes</td>
 +
</tr>
 +
}}
 +
<br>
 +
 
 +
==== Add get() and set() Methods====
 +
Add <tt>get(String)</tt> and <tt>set(String, Object)</tt> methods to the entity.
 +
 
 +
The <tt>get()</tt> method returns a value by property name and the <tt>set()</tt> method stores a value by property name. The default names for these methods are <tt>get</tt> and <tt>set</tt>, and they can be overridden with the <tt>@VirtualAccessMethods</tt> annotation.
 +
 
 +
EclipseLink weaves these methods if weaving is enabled, which provides support for lazy loading, change tracking, fetch groups, and internal optimizations. You must use the the <tt>get(String)</tt> and <tt>set(String, Object)</tt> signatures, or else weaving will not work.
 +
 
 +
{{EclipseLink_Note
 +
|note=Weaving is not supported when using virtual access methods with OneToOne mappings. If attempted, an exception will be thrown.
 +
}}
  
===Annotating Entities===
+
==== Add a Data Structure ====
Use @VirtualAccessMethods to annotate entities to allow flexible mappings, for example:
+
 
 +
Add a data structure to store the extended attributes and values, that is, the virtual mappings. These can then be mapped to the database. See [[#Providing Additional Mappings| Providing Additional Mappings]].
 +
 
 +
A common way to store the virtual mappings is in a <tt>Map</tt> (as shown in the examples in this topic), but you can use other ways, as well. For example you could store the virtual mappings in a directory system.
 +
 
 +
When using field-based access, annotate the data structure with <tt>@Transient</tt> so it cannot use it for another mapping. When using property-based access, <tt>@Transient'</tt> is unnecessary.
 +
 
 +
====Example====
 +
 
 +
The following example shows an entity that uses property access.
  
 
<source lang="java">
 
<source lang="java">
Line 40: Line 96:
 
   public class Customer{
 
   public class Customer{
 
   
 
   
 +
    @Id
 +
    private int id;
 
...
 
...
 
   
 
   
 
     @Transient
 
     @Transient
 
     private Map<String, Object> extensions;
 
     private Map<String, Object> extensions;
+
 
 
     public <T> T get(String name) {
 
     public <T> T get(String name) {
 
         return (T) extentions.get(name);
 
         return (T) extentions.get(name);
Line 53: Line 111:
 
     }
 
     }
 
</source>
 
</source>
 +
 +
====Using XML====
 +
As an alternative to, or in addition to, using <tt>@VirtualAccessMethods</tt>, you can use the <tt><access></tt> and <tt><access-methods></tt> elements, for example:
 +
 +
<source lang="xml">
 +
<access>VIRTUAL</access>
 +
<access-methods set-method="get" get-method="set"/>
 +
</source>
 +
 +
''''''REVIEWERS: // Is this correct? Is this adequate?//''''''
  
 
===Designing the Schema===
 
===Designing the Schema===
  
When you design your schema, provide enough extra columns in the tables to accommodate the number of flexible mappings to allow. For example, the following table has three predefined columns and three columns for adding mappings later.
+
Provide database tables with extra columns for storing flexible mapping data. For example, the following Customer table includes two predefined columns, ID and NAME, and three flexible columns, FLEX_COL1, FLEX_COL2, FLEX_COL3:
 +
 
 +
*CUSTOMER
 +
**INTEGER ID
 +
**VARCHAR NAME
 +
**VARCHAR FLEX_COL1
 +
**VARCHAR FLEX_COL2
 +
**VARCHAR FLEX_CO31
  
For example, consider the following Customer table that includes three flexible columns, FLEX_COL1, FLEX_COL2, FLEX_COL3:
+
You can then specify which of those flex columns should be used to persist an extended attribute, as described below, in [[#Providing Additional Mappings| Providing Additional Mappings]].
  
CUSTOMER
 
INTEGER ID
 
VARCHAR NAME
 
VARCHAR FLEX_COL1
 
VARCHAR FLEX_COL2
 
VARCHAR FLEX_CO31
 
 
===Providing Additional Mappings===
 
===Providing Additional Mappings===
  
To provide additional mappings, add the mappings to the eclipselink-orm.xml file, for example:
+
To provide additional mappings, add the mappings to the <tt>eclipselink-orm.xml</tt> file, for example:
 
   
 
   
 
<source lang="xml">
 
<source lang="xml">
Line 77: Line 146:
 
</source>
 
</source>
  
‘’’’’Are there any limitations on the types of mappings that support this? I think I saw this in the original design doc.’’’’’
+
'''''//REVIEWERS: Are there any limitations on the types of mappings that support flexible mappings? Also, do you think anything more should be said about what you have to do in eclipselink-orm.xml?//'''''
===Configure persistence.xml===
+
  
Configure persistence unit properties in persistence.xml to indicate that the application should use the file. For example:
+
* ''' I think that part of this will be addressed by anything we do to document using <access-methods> to specify Virtual mappings'''--[[User:Tom.ware.oracle.com|Tom.ware.oracle.com]] 16:04, 28 June 2011 (UTC)
 +
* ''' The XML file simply gets treated as another XML file in the list of XML files. As long as you obey all the rules related to what can be overridden, you can use any kind of mapping.  The challenge in using non-virtual mappings is how to have the data structures that support them make sense when the document is not there. e.g. if you're going to have an extension that uses an instance variable, for the instances of the application that don't use that extension file, how is that instance variable treated - JPA will likely try to use it for a mapping using its defaulting-rules''' --[[User:Tom.ware.oracle.com|Tom.ware.oracle.com]] 16:04, 28 June 2011 (UTC)
  
‘’’’’“use the file”? what wording would be better here? orig said “Use persistence unit properties to get your application to use the file:”’’’’’
+
===Configuring persistence.xml===
 +
 
 +
Configure persistence unit properties in <tt>persistence.xml</tt> to indicate that the application should retrieve the flexible mappings from the <tt>eclipselink-orm.xml</tt> file,. For example:
 +
 
 +
'''''//REVIEWERS Did I get that intro right? Would different wording be better here? The design doc said “Use persistence unit properties to get your application to use the file."//'''''
 +
 
 +
* '''Both persistence unit propeties and persistence.xml are legitimate use cases.  We should describe both.  persistence.xml allows either a default, or a single-user file that can be changed.  persistence unit properties allow specification of the file at runtime and provides a more dynamic experience.'''--[[User:Tom.ware.oracle.com|Tom.ware.oracle.com]] 16:06, 28 June 2011 (UTC)
  
 
<source lang="xml">
 
<source lang="xml">
Line 89: Line 164:
 
</source>
 
</source>
  
‘’’’’Say more about what you are doing here. It looks like it is just defining a name/value pair. I think this is standard stuff: you just define this and then use it somewhere else.’’’’’
+
'''''//REVIEWERS What more can be  said about these? See my related questions below, under [[#Configuring the EntityManagerFactory and the Metadata Repository | Configuring the EntityManagerFactory and the Metadata Repository]].//'''''
 
+
 
+
‘’’’’Deleted Requirements section. Come back here at the end and see if you’ve handled it all.’’’’
+
 
+
 
+
==Configuration ==
+
 
+
===Metadata Configuration===
+
 
+
Extensions are supported using the VIRTUAL access type. Virtual Access type allows properties to be set through a getter that takes an attribute name as an argument and a setter that takes an argument name and a value as an argument.  
+
 
+
  
These annotations will have the same effect as using the eclipselink-orm.xml construct <access-methods> at a class level. They default which methods are used by virtual mappings.  
+
* '''Maybe the two sections should go together.  We could mention that by default we support using a file at a URL, but it is possible to also override how the repository works and then go into details.'''--[[User:Tom.ware.oracle.com|Tom.ware.oracle.com]] 17:20, 28 June 2011 (UTC)
  
EclipseLink weaves these methods if weaving is enabled. This weaving will provide equivalent functionality to weaving for PROPERTY and FIELD access. (e.g. change tracking, fetch groups, etc) An Equivalent <extensible> tag will be added at the class level in XML.  
+
==Examples ==
 +
The following examples illustrate variations on configuring extensible entities.
  
====Examples ====
+
====Example 1====
  
‘’Example 1’’ illustrates the following:  
+
''Example 1'' illustrates the following:  
o Field Access for non extension fields  
+
*Field access is used for non-extension fields.
o Virtual Access for extension fields uses defaults (get(String), set(String, Object))  
+
*Virtual access is used for extension fields, using defaults <tt>(get(String)</tt> and <tt>set(String, Object))</tt> .
o The get(String) and set(String, Object) method will be woven, even if no mappings use them, because of the presence of @Extensible << I don’t see @Extensible
+
*The <tt>get(String)</tt> and <tt>set(String, Object)</tt> methods will be woven, even if no mappings use them, because of the presence of <tt>@VirtualAccessMethods</tt>.
o Extensions are mapped in a portable way by specifying @Transient << I don’t see @Transient
+
*Extensions are mapped in a portable way by specifying <tt>@Transient</tt>.
  
 
Example 1
 
Example 1
Line 142: Line 207:
 
</source>
 
</source>
  
‘’Example 2’’ illustrates the following:
+
====Example 2====
  
o Field Access for non extension fields
+
Example 2  illustrates the following:
o Extensions mapped in a portable way - @Transient
+
o The @VirtualAccessMethods annotation overrides methods to be used for getting and setting.
+
o The getExtension(String) and setExtension(String, Object) methods will be woven, even if no mappings use them, because of the presence of @Extensible << I don’t see @Extensible
+
o The XML for extended mapping indicates which get and set method to use .
+
  
 +
*Field access is used for non-extension fields.
 +
* The <tt>@VirtualAccessMethods</tt> annotation overrides methods to be used for getting and setting.
 +
*The <tt>get(String)</tt> and <tt>set(String, Object)</tt> methods will be woven, even if no mappings use them, because of the presence of <tt>@VirtualAccessMethods</tt>.<br>
 +
*Extensions are mapped in a portable way by specifying <tt>@Transient</tt>.
 +
* The XML for extended mapping indicates which <tt>get()</tt> and <tt>set()</tt> method to use.
  
 
Example 2  
 
Example 2  
Line 187: Line 253:
 
</source>
 
</source>
  
‘’Example 3’’ illustrates the following:
+
====Example 3====
  
* Property Access for non extension fields  
+
Example 3  illustrates the following:
* Virtual Access for extension fields uses defaults <tt>(get(String), set(String, Object))</tt>  
+
 
* The extensions are mapped in a portable way; no @Transient is required because of Property access  
+
* Property access is used for non-extension fields.
* The <tt>get(String)</tt> and <tt>set(String, Object) </tt> methods will be woven, even if no mappings use them, because of the presence of <tt>@Extensible</tt>  
+
*Virtual access is used for extension fields, using defaults <tt>(get(String)</tt> and <tt>set(String, Object)) </tt>  
 +
* The extensions are mapped in a portable way. <tt>@Transient</tt> is not required, because property access is used.
 +
* The <tt>get(String)</tt> and <tt>set(String, Object)</tt> methods will be woven, even if no mappings use them, because of the presence of <tt>@VirtualAccessMethods</tt>.
 +
<br>
  
 
<source lang="java">
 
<source lang="java">
Line 219: Line 288:
 
</source>
 
</source>
  
===EntityManagerFactory and Metadata Repository ===
+
<span id="this">
 +
== Configuring the EntityManagerFactory and the Metadata Repository ==
  
Extensions will be added at bootstrap time through access to a metadata repository. A Metadata Repository will accessed through a class that provides methods to retrieve the metadata it holds.  
+
Extensions are added at bootstrap time through access to a metadata repository. The metadata repository is accessed through a class that provides methods to retrieve the metadata it holds. The current release supports XML repositories.
  
The user will specifiy the class to use and any configuration information for the metadata repository through persistence unit properties. As an EntityManagerFactory bootstraps, if metadata repository information is provided, the EMF will check the metadata repository for additional mapping information and integrate it into the metadata it uses to bootstrap.
+
Specify the class to use and any configuration information for the metadata repository through persistence unit properties. The entity manager factory integrates additional mapping information from the metadata repository into the metadata it uses to bootstrap.  
EclipseLink will initially ship with the capability of connecting to two types of metadata repository.  
+
  
XML (high priority) - information about extensions is stored in XML
+
You can provide your own implementation of the class to access the metadata repository.  
Database Table (medium priority) - information about extensions is stored in a database table
+
Each metadata repository access class must specify an individual set of properties to use to connect to the repository.
Additionally, the user will be able to provide an implementation of the class that access the metadata repository.  
+
Each metadata repository access class will specify an individual set of properties to use to connect to the repository  
+
Examples
+
XML File
+
+
<source lang="xml">
+
<property name="eclipselink.metadata-source" value="XML"/>
+
  <property name="eclipselink.metadata-source.xml.url" value="foo://bar"/>
+
</source>
+
  
User-Specified
+
You can subclass either of the following: *<tt>org.eclipse.persistence.internal.jpa.extensions.MetadataRepository</tt> *<tt>org.eclipse.persistence.internal.jpa.extensions.XMLMetadataRepository</tt>
 +
 
 +
====Example====
 +
In the following example, the properties that begin with <tt>com.foo</tt> are defined by the implementor.
  
 
<source lang="xml">
 
<source lang="xml">
 
<property name="eclipselink.metadata-source" value="com.foo.MetadataRepository"/>
 
<property name="eclipselink.metadata-source" value="com.foo.MetadataRepository"/>
  <property name="com.foo.MetadataRepository.location" value="foo://bar"/>
+
<property name="com.foo.MetadataRepository.location" value="foo://bar"/>
  <property name="com.foo.MetadataRepository.extra-data" value="foo-bar"/>
+
<property name="com.foo.MetadataRepository.extra-data" value="foo-bar"/>
 
</source>
 
</source>
  
Note: The implementer of <tt>com.foo.MetadataRepository</tt> will be free to choose the properties that their implementation requires.
+
====Refreshing the Metadata Repository====
==Design ==
+
====Configuration ====
+
Please use the examples above as a guideline configuration XML and annotations. Note that the configuration options to allow a mapping to use VIRTUAL access have been available in EclipseLink for several releases. We will be using those configuration options as they exist and any changes to those will be handled as bugs rather than through this design document.
+
====Weaving ====
+
The intial VIRTUAL access feature did not include weaving of the get and set methods. As part of the extensions feature will will add weaving of get and set methods that use virtual access. The initial implementation will not support OneToOne mappings and throw an exception at Transformer construction time if weaving is requested for a VIRTUAL mapping that is OneToOne.
+
  
Get method
+
If you change the metadata and you want an <tt>EntityManager</tt> based on the new metadata, you must call <tt>refreshMetadata()</tt> on the <tt>EntityManagerFactory</tt> to refresh the data. The next <tt>EntityManager</tt> will be based on the new metadata. 
  
Original
+
<tt>refreshMetadata</tt> takes a <tt>Map</tt> of properties, and that map of properties can be used to override the properties previously defined for the metadata-source.
<source lang="java">
+
public <T> T get(String name) {
+
        return (T) getExtensions().get(name);
+
    }
+
</source>
+
Weaved
+
<source lang="java">
+
public Object get(String name)
+
    {
+
        _persistence_checkFetched(name);
+
        return getExtensions().get(name);
+
    }
+
</source>
+
  
Set method
 
Original
 
<source lang="java">
 
public Object set(String name, Object value)
 
    {
 
        return getExtensions().put(name, value);
 
  
    }
+
{{EclipseLink_JPA }}
</source>
+
Weaved
+
<source lang="java">
+
public Object set(String name, Object value)
+
    {
+
        Object obj = null;
+
        if(_persistence_listener != null)
+
        {
+
            obj = get(name);
+
        } else
+
        {
+
            _persistence_checkFetchedForSet(name);
+
        }
+
        _persistence_propertyChange(name, obj, value);
+
        return getExtensions().put(name, value);
+
    }
+
</source>
+
 
+
To allow weaving, RelationalDescriptor will have a list virtual methods added. This list will be used at transformer-construction time to allow EclipseLink to know which methods it should weave.
+
 
+
<source lang="java">
+
 
+
/** The methods that are used by virtual attributes as getter methods and setter methods. 
+
    * These will be used by our weaver to properly weave those methods
+
    **/
+
    protected List<VirtualAccessMethods> virtualMethods = null;
+
</source>
+
 
+
===EntityManagerFactory ===
+
 
+
====Bootstrap ====
+
 
+
<tt>EntityManagerFactory</tt> bootstrapping occurs within <tt>EntityManagerSetupImpl</tt>. In the <tt>predeploy</tt> method, there is code that obtains the orm.xml files that contain metadata. At that point, the metadata repository will be consulted. It will provide additional metadata information in the same format as is obtained from the orm.xml file.
+
 
+
=== Refresh ===
+
 
+
A mechanism will be provided that allows a user to tell a Metadata repository to refresh. That mechanism will take two forms.
+
A direct refresh API call
+
A RemoteCommandManager command that causes all subscribed EntityManagerFactories to refresh themselves as described above.
+
Refresh will be supported by adding an additional proxy to our EntityManagerFactory archtecture.
+
Current: EntityManagerFactoryImpl -> ServerSession
+
New: EntityManagerFactoryWrapper implements EntityManagerFactory -> EntityManagerFactoryImpl -> ServerSession
+
EntityManagerFactoryWrapper will implement:
+
public void refreshMetadata()
+
In both cases, a live EntityManager holds a reference to EntityManagerFactoryImpl
+
When a call is made to refreshMetadata(), EntityManagerFactoryWrapper will bootstrap a new EntityManagerFactoryImpl and use it as the basis for any new EntityManagers. The old EntityManagerFactoryImpl will continue to be available until the last EntityManager is no longer used, at which point we will rely on garbage collection to clean it up.
+
Metadata Source
+
An implementation of MetadataSoruce will access metadata for extensions. Metadata is accessed in the form of an eclipselink-orm.xml file.
+
package org.eclipse.persistence.jpa.metadata;
+
+
public interface MetadataSource{
+
+
    /**
+
    * ADVANCED:
+
    * In most cases, this method should not be overridden.  The implementation of
+
    * this method uses getEntityMappingsReader() to obtain a reader that will
+
    * that reads a stream in the eclipselink-orm.xml format
+
    * Advanced implementations of MetadataRepository have to option of overriding
+
    * this method.
+
    * @return XMLEntityMappings which are then merged in using existing metadata
+
    * processing at bootstrap time when creating an entityManager
+
    */
+
    public XMLEntityMappings getMetadata(Properties properties, ClassLoader loader)
+
Additionally, an adapter class will be provided that implements MetadataSource containing stubbed out methods. Customers will be encouraged to implement a MetadataSource by subclasing the adapter class rather than directly implementing the interface. This strategy will allow them to tranaparently absorb any new versions of the interface in new EclipseLink versions.
+
XMLMetadataSource
+
The first implementation of MetadataSource provided by EclipseLink will access a simple XML File.
+
It will provide an implementation of getMetadata(properties, classlaoder) that uses the property "eclipselink.metadata-repository.xml-file.url", specified like this:
+
 
+
<source lang="xml">
+
<property name="eclipselink.metadata-source.xml.url" value="foo://bar"/>
+
 
+
To create an input stream on the eclipselink-orm.xml file at URL: "foo://bar"/" and build an XMLEntityMappings using our existing EclipseLink ORM parsing code.
+
Writing to a metadata repository
+
In the initial implementation writing to the metadata repository will be left up to the user.
+
Remote Command Manager
+
A Command for RemoteCommandManager will be implemented that triggers a refreshMetadata() call on all subscribed EntityManagerFactories.
+
Design is in progress and will be added as it becomes available
+
Future Enhancements
+
Weaving of OneToOne mappings
+
Implement support for weaving of non-basic VIRTUAL mappings
+
Handle OneToOneMappings
+
Handle indirection
+
Allow metadata to be updated with an in-memory structure
+
From GlassFish team:
+
Programmatic API to call into EclipseLink to "push" the extension definitions.
+
The data exchanged between the caller and EclipseLink via API should be in a format that just refers to extension information and not a generic data structure.
+
The API call should be on an EclipseLink artifact that does not trigger deploy. That is it should be on an artifact at EMF level.
+
Database Metadata Source
+
Provide an implementation of Metadata Source that reads from a database.
+
Writing to a metadata Source
+
Provide API to write to the XMLFile and DatabaseMetadata Sources.
+
Configuration of muliple getter and setter methods
+
Allow annotations and xml to specify a list of methods for VIRTUAL mappings to weave
+
Appendices
+
Appendix 1: Alternatives Considered
+
http://wiki.eclipse.org/EclipseLink/DesignDocs/335601
+
Appendix 2: Annotations
+
<source lang="java">
+
/**
+
* Specifies that this class contains virtual attributes.
+
* This annotation is used in an EclipseLink-specific way to define
+
* access methods used by mappings with accessType=VIRTUAL.
+
* The xml-equivalent is the <access-methods> tag
+
*/
+
@Documented
+
@Target(TYPE)
+
@Retention(RUNTIME)
+
public @interface VirtualAccessMethods {
+
+
    /**
+
    * (Optional) The name of the getter method to use for the virtual property
+
    * This method must take a single java.lang.String parameter and return a java.lang.Object.
+
    * If setMethod is specified, getMethod must be specified
+
    */
+
    String get() default "get";
+
+
    /**
+
    * (Optional) The name of the setter method to use for the virtual property
+
    * This method must take a java.lang.String parameter and a java.lang.Object parameter.
+
    * If getMethod is specified, setMethod must be specified
+
    */
+
    String set() default "set";
+
}
+
</source>
+

Latest revision as of 12:46, 4 July 2011

EclipseLink JPA

Eclipselink-logo.gif
EclipseLink
Website
Download
Community
Mailing ListForumsIRCmattermost
Issues
OpenHelp WantedBug Day
Contribute
Browse Source

******SANDBOX VERSION******

This topic is currently under review.

Extensible Entities

EL NewIn.png New in version 2.3.



.

Use the @VirtualAccessMethods annotation to specify that an entity is extensible. By using virtual properties in an extensible entity, you can specify mappings external to the entity. This allows you to modify the mappings without modifying the entity source file and without redeploying the entity's persistence unit.

Extensible entities are useful in a multi-tenant (or Software-as-a-Service) environment where a shared, generic application can be used by multiple clients (tenants). Tenants have private access to their own data, as well as to data shared with other tenants. See also Single-Table Multi-Tenancy.

Using extensible entities, you can:

  • Build an application where some mappings are common to all users and some mappings are user-specific.
  • Add mappings to an application after it is made available to a customer (even post-deployment).
  • Use the same EntityManagerFactory to work with data after mappings have changed.
  • Provide an additional source of metadata to be used by an application.

To create and support an extensible entity,

  1. Configure the entity. See Configuring the Entity.
  2. Include flexible columns in the database table to store the additional data. See Designing the Schema.
  3. Specify extended mappings in the eclipselink-orm.xml file. See Providing Additional Mappings
  4. Configure persistence.xml. See Configuring persistence.xml.

Configuring the Entity

To configure the entity,

  1. Annotate with @VirtualAccessMethods
  2. Add get() and set() methods
  3. Add a data structure

Annotate with @VirtualAccessMethods

Annotate the entity with @VirtualAccessMethods to specify that it is extensible and to define virtual properties.

@VirtualAccessMethods Attributes
Attribute Description Default Required?
get The name of the getter method to use for the virtual property This method must take a single java.lang.String parameter and return a java.lang.Object. get Yes
set The name of the setter method to use for the virtual property This method must take a java.lang.String parameter and return a java.lang.Object parameter. set Yes


Add get() and set() Methods

Add get(String) and set(String, Object) methods to the entity.

The get() method returns a value by property name and the set() method stores a value by property name. The default names for these methods are get and set, and they can be overridden with the @VirtualAccessMethods annotation.

EclipseLink weaves these methods if weaving is enabled, which provides support for lazy loading, change tracking, fetch groups, and internal optimizations. You must use the the get(String) and set(String, Object) signatures, or else weaving will not work.

Elug note icon.png

Note: Weaving is not supported when using virtual access methods with OneToOne mappings. If attempted, an exception will be thrown.

Add a Data Structure

Add a data structure to store the extended attributes and values, that is, the virtual mappings. These can then be mapped to the database. See Providing Additional Mappings.

A common way to store the virtual mappings is in a Map (as shown in the examples in this topic), but you can use other ways, as well. For example you could store the virtual mappings in a directory system.

When using field-based access, annotate the data structure with @Transient so it cannot use it for another mapping. When using property-based access, @Transient' is unnecessary.

Example

The following example shows an entity that uses property access.

@Entity
  @VirtualAccessMethods
  public class Customer{
 
    @Id
    private int id;
...
 
    @Transient
    private Map<String, Object> extensions;
 
    public <T> T get(String name) {
        return (T) extentions.get(name);
    }
 
    public Object set(String name, Object value) {
        return extensions.put(name, value);
    }

Using XML

As an alternative to, or in addition to, using @VirtualAccessMethods, you can use the <access> and <access-methods> elements, for example:

<access>VIRTUAL</access>
<access-methods set-method="get" get-method="set"/>

'REVIEWERS: // Is this correct? Is this adequate?//'

Designing the Schema

Provide database tables with extra columns for storing flexible mapping data. For example, the following Customer table includes two predefined columns, ID and NAME, and three flexible columns, FLEX_COL1, FLEX_COL2, FLEX_COL3:

  • CUSTOMER
    • INTEGER ID
    • VARCHAR NAME
    • VARCHAR FLEX_COL1
    • VARCHAR FLEX_COL2
    • VARCHAR FLEX_CO31

You can then specify which of those flex columns should be used to persist an extended attribute, as described below, in Providing Additional Mappings.

Providing Additional Mappings

To provide additional mappings, add the mappings to the eclipselink-orm.xml file, for example:

<basic name="idNumber" attribute-type="String">
  <column name="FLEX_COL1"/>
  <access-methods get-method="get" set-method="set"/>
</basic>

//REVIEWERS: Are there any limitations on the types of mappings that support flexible mappings? Also, do you think anything more should be said about what you have to do in eclipselink-orm.xml?//

  • I think that part of this will be addressed by anything we do to document using <access-methods> to specify Virtual mappings--Tom.ware.oracle.com 16:04, 28 June 2011 (UTC)
  • The XML file simply gets treated as another XML file in the list of XML files. As long as you obey all the rules related to what can be overridden, you can use any kind of mapping. The challenge in using non-virtual mappings is how to have the data structures that support them make sense when the document is not there. e.g. if you're going to have an extension that uses an instance variable, for the instances of the application that don't use that extension file, how is that instance variable treated - JPA will likely try to use it for a mapping using its defaulting-rules --Tom.ware.oracle.com 16:04, 28 June 2011 (UTC)

Configuring persistence.xml

Configure persistence unit properties in persistence.xml to indicate that the application should retrieve the flexible mappings from the eclipselink-orm.xml file,. For example:

//REVIEWERS Did I get that intro right? Would different wording be better here? The design doc said “Use persistence unit properties to get your application to use the file."//

  • Both persistence unit propeties and persistence.xml are legitimate use cases. We should describe both. persistence.xml allows either a default, or a single-user file that can be changed. persistence unit properties allow specification of the file at runtime and provides a more dynamic experience.--Tom.ware.oracle.com 16:06, 28 June 2011 (UTC)
<property name="eclipselink.metadata-source" value="XML"/>
<property name="eclipselink.metadata-source.xml.url" value="foo://bar"/>

//REVIEWERS What more can be said about these? See my related questions below, under Configuring the EntityManagerFactory and the Metadata Repository.//

  • Maybe the two sections should go together. We could mention that by default we support using a file at a URL, but it is possible to also override how the repository works and then go into details.--Tom.ware.oracle.com 17:20, 28 June 2011 (UTC)

Examples

The following examples illustrate variations on configuring extensible entities.

Example 1

Example 1 illustrates the following:

  • Field access is used for non-extension fields.
  • Virtual access is used for extension fields, using defaults (get(String) and set(String, Object)) .
  • The get(String) and set(String, Object) methods will be woven, even if no mappings use them, because of the presence of @VirtualAccessMethods.
  • Extensions are mapped in a portable way by specifying @Transient.

Example 1

@Entity
  @VirtualAccessMethods
  public class Address {
 
    @Id
    private int id;
 
    @Transient
    private Map<String, Object> extensions;
 
    public int getId(){
        return id;
    }
 
    public <T> T get(String name) {
        return (T) extentions.get(name);
    }
 
    public Object set(String name, Object value) {
        return extensions.put(name, value);
    }
 
...

Example 2

Example 2 illustrates the following:

  • Field access is used for non-extension fields.
  • The @VirtualAccessMethods annotation overrides methods to be used for getting and setting.
  • The get(String) and set(String, Object) methods will be woven, even if no mappings use them, because of the presence of @VirtualAccessMethods.
  • Extensions are mapped in a portable way by specifying @Transient.
  • The XML for extended mapping indicates which get() and set() method to use.

Example 2

@Entity
  @VirtualAccessMethods(get="getExtension", set="setExtension")
  public class Address {
 
    @Id
    private int id;
 
    @Transient
    private Map<String, Object> extensions;
 
    public int getId(){
        return id;
    }
 
    public <T> T getExtension(String name) {
        return (T) extensions.get(name);
    }
 
    public Object setExtension(String name, Object value) {
        return extensions.put(name, value);
    }
 
...
<basic name="name" attribute-type="String">
      <column name="FLEX_1"/>
      <access-methods get-method="getExtension" set-method="setExtension"/>
    </basic>

Example 3

Example 3 illustrates the following:

  • Property access is used for non-extension fields.
  • Virtual access is used for extension fields, using defaults (get(String) and set(String, Object))
  • The extensions are mapped in a portable way. @Transient is not required, because property access is used.
  • The get(String) and set(String, Object) methods will be woven, even if no mappings use them, because of the presence of @VirtualAccessMethods.


@Entity
  @VirtualAccessMethods
  public class Address {
 
    private int id;
 
    private Map<String, Object> extensions;
 
    @Id
    public int getId(){
        return id;
    }
 
    public <T> T get(String name) {
        return (T) extensions.get(name);
    }
 
    public Object set(String name, Object value) {
        return extensions.put(name, value);
    }
 
...

Configuring the EntityManagerFactory and the Metadata Repository

Extensions are added at bootstrap time through access to a metadata repository. The metadata repository is accessed through a class that provides methods to retrieve the metadata it holds. The current release supports XML repositories.

Specify the class to use and any configuration information for the metadata repository through persistence unit properties. The entity manager factory integrates additional mapping information from the metadata repository into the metadata it uses to bootstrap.

You can provide your own implementation of the class to access the metadata repository. Each metadata repository access class must specify an individual set of properties to use to connect to the repository.

You can subclass either of the following: *org.eclipse.persistence.internal.jpa.extensions.MetadataRepository *org.eclipse.persistence.internal.jpa.extensions.XMLMetadataRepository

Example

In the following example, the properties that begin with com.foo are defined by the implementor.

<property name="eclipselink.metadata-source" value="com.foo.MetadataRepository"/>
<property name="com.foo.MetadataRepository.location" value="foo://bar"/>
<property name="com.foo.MetadataRepository.extra-data" value="foo-bar"/>

Refreshing the Metadata Repository

If you change the metadata and you want an EntityManager based on the new metadata, you must call refreshMetadata() on the EntityManagerFactory to refresh the data. The next EntityManager will be based on the new metadata.

refreshMetadata takes a Map of properties, and that map of properties can be used to override the properties previously defined for the metadata-source.


Eclipselink-logo.gif
Version: DRAFT
Other versions...

Back to the top