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
Line 1: Line 1:
{{ECLIPSELINK_USERGUIDE
+
{{EclipseLink_UserGuide
 
|info=y
 
|info=y
 
|toc=n
 
|toc=n

Revision as of 13:29, 24 June 2011

EclipseLink JPA

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

Elug api package icon.png Key API

  • []

Elug example icon.png Examples


Extensible Entities

This feature is new in EclipseLink 2.3.

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 eclipselink-orm.xml mapping file. These extended mappings are always? stored and managed externally, which allows you to define new mappings while the application is running.

Question: Will there be other kinds of extensible entities? That is, will there be extensible entities that use an alternative to flex columns (as the earlier design doc pondered)? What I really want to know is this: should I introduce this topic saying that this is what extensible entities are? Or should I say this is one kind of extensible entity?

Extensible entities provide flexibility for xxxxxxxxx Template:Mappings only or properties, including mapping?

You can use such extended entities to do the following:

  • 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.

Extensible entities are 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 extend the entities and take advantage of flexible columns, you must do the following:

  • Annotate entities to allow flexible mappings.
  • Provide facilities to store the additional data.
  • more

Annotating Entities

Use the @VirtualAccessMethods annotation to annotate entities to allow flexible Template:Spec says "flexible: - should it be "extensible"? mappings, for example:

@Entity
  @VirtualAccessMethods
  public class Customer{
 
...
 
    @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);
    }

Designing the Schema

Design a schema with extra columns for storing storedetermines how the persistence provider accesses the

       state of an entity or embedded object.

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.

For example, consider the following Customer table that includes three flexible columns, FLEX_COL1, FLEX_COL2, FLEX_COL3:

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

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>

Are there any limitations on the types of mappings that support this? I think I saw this in the original design doc.

Configure persistence.xml

Configure persistence unit properties in persistence.xml to indicate that the application should use the file. For example:

“use the file”? what wording would be better here? orig said “Use persistence unit properties to get your application to use the file:”

<property name="eclipselink.metadata-source" value="XML"/>
<property name="eclipselink.metadata-source.xml.url" value="foo://bar"/>

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.


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.

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

Example 1 illustrates the following: o Field Access for non extension fields o Virtual Access for extension fields uses defaults (get(String), set(String, Object)) 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 o Extensions are mapped in a portable way by specifying @Transient << I don't see @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 illustrates the following:

  • Field Access for non extension fields
  • Extensions mapped in a portable way - @Transient
  • The @VirtualAccessMethods annotation overrides methods to be used for getting and setting.
  • 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
  • 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 illustrates the following:

  • Property Access for non extension fields
  • Virtual Access for extension fields uses defaults (get(String), set(String, Object))
  • The extensions are mapped in a portable way; no @Transient is required because of Property access
  • The get(String) and set(String, Object) methods will be woven, even if no mappings use them, because of the presence of @Extensible
@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);
    }
 
...

EntityManagerFactory and 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.

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. 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 Database Table (medium priority) - information about extensions is stored in a database table 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

<property name="eclipselink.metadata-source" value="XML"/>
  <property name="eclipselink.metadata-source.xml.url" value="foo://bar"/>

User-Specified

<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"/>

Note: The implementer of com.foo.MetadataRepository will be free to choose the properties that their implementation requires.

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

Original

public <T> T get(String name) {
        return (T) getExtensions().get(name);
    }

Weaved

public Object get(String name)
    {
        _persistence_checkFetched(name);
        return getExtensions().get(name);
    }

Set method Original

public Object set(String name, Object value)
    {
        return getExtensions().put(name, value);
 
    }

Weaved

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);
    }

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.

/** 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;

EntityManagerFactory

Bootstrap

EntityManagerFactory bootstrapping occurs within EntityManagerSetupImpl. In the predeploy 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. You should implement a MetadataSource by subclassing the adapter class rather than directly implementing the interface. This strategy will allows you to transparently 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:

<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

/**
 * 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";
}

Back to the top