Jump to: navigation, search

Difference between revisions of "EclipseLink/Examples/MOXy/MultipleBindingsFiles"

(Customizations for Tenant 1)
 
(4 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
== Introduction ==  
 
== Introduction ==  
EclipseLink MOXy provides the ability to augment the annotation metadata with an XML bindings file. As of version 2.3, EclipseLink can now process multiple bindings files from different locations, and create a merged set of metadata.
+
EclipseLink MOXy provides the ability to augment the annotation metadata with an XML bindings file. As of version 2.3, EclipseLink MOXy can now process multiple bindings files from different locations, and create a merged set of metadata.
  
Sample use case: 1. Initial metadata is specified with a metadata file. 2. Second version modifies the metadata with an additional XML bindings file. 3. Subsequent versions continue to modify with additional bindings files.
+
Sample use case:
 +
# Initial metadata is specified with a metadata file.
 +
# Second version modifies the metadata with an additional XML bindings file.
 +
# Subsequent versions continue to modify with additional bindings files.
  
With the metadata layered in this way a JAXBContext could be created to represent any version of the XML document.
 
  
By using this in conjunction with a multi-tenant architecture, you can define a base set of metadata using one XML Bindings file, and then an additional file for each tenant. This example will be based on the object model from the [http://wiki.eclipse.org/EclipseLink/Examples/MOXy/Extensible EclipseLink Moxy Extensibile] example.
+
With the metadata layered in this way a '''JAXBContext''' could be created to represent any version of the XML document.
 +
 
 +
By using this in conjunction with a multi-tenant architecture, you can define a base set of metadata using one XML Bindings file, and then an additional file for each tenant. This example will be based on the object model from the [http://wiki.eclipse.org/EclipseLink/Examples/MOXy/Extensible EclipseLink MOXy Extensibile] example.
 +
 
  
 
== Java Model ==
 
== Java Model ==
 +
 
'''ExtensibleBase'''
 
'''ExtensibleBase'''
 +
 
<source lang="java">
 
<source lang="java">
 
package examples.virtual;
 
package examples.virtual;
Line 33: Line 40:
 
         extensions.put(property, value);
 
         extensions.put(property, value);
 
     }
 
     }
 +
 
}
 
}
 
</source>
 
</source>
Line 122: Line 130:
  
 
== Base XML Bindings ==  
 
== Base XML Bindings ==  
The base XML Bindings file will specify some initial basic meta-data that will be used for all tenants.  
+
 
 +
The base XML Bindings file will specify some initial basic metadata that will be used for all tenants.  
 +
 
 
* Root Element name for Customer
 
* Root Element name for Customer
 
* Add XmlValue to PhoneNumber
 
* Add XmlValue to PhoneNumber
 +
  
 
'''base-bindings.xml'''
 
'''base-bindings.xml'''
 +
 
<source lang="xml">
 
<source lang="xml">
 
<?xml version="1.0"?>
 
<?xml version="1.0"?>
Line 144: Line 156:
 
</xml-bindings>
 
</xml-bindings>
 
</source>
 
</source>
 +
  
 
== Customizations for Tenant 1 ==
 
== Customizations for Tenant 1 ==
 +
 
The first tenant is an online sporting goods store, that requires the following extensions to their model:
 
The first tenant is an online sporting goods store, that requires the following extensions to their model:
  
Line 153: Line 167:
 
* A collection of contact phone numbers
 
* A collection of contact phone numbers
 
* Type of phone number (i.e. home, work, or cell)
 
* Type of phone number (i.e. home, work, or cell)
 +
  
 
The metadata for additional virtual properties is supplied through this tenant's specific EclipseLink XML file.  
 
The metadata for additional virtual properties is supplied through this tenant's specific EclipseLink XML file.  
  
 
'''binding-tenant1.xml'''
 
'''binding-tenant1.xml'''
 +
 
<source lang="xml">
 
<source lang="xml">
 
<?xml version="1.0"?>
 
<?xml version="1.0"?>
Line 193: Line 209:
 
</source>
 
</source>
  
== Creating The Context ==  
+
 
To create a context using multiple bindings files, pass in a list of sources instead of a single source. A source can be a File, a Stream, or a String representing either a URL or a classpath reference.  
+
== Customizations for Tenant 2 ==
 +
 
 +
The second tenant is a streaming media provider that offers on-demand movies and music to its subscribers.  It requires a different set of extensions to the core model:
 +
 
 +
* A single contact phone number
 +
 
 +
 
 +
For this tenant we will also leverage an additional mapping file to customize the mapping of the real properties:
 +
 
 +
'''binding-tenant2.xml'''
 +
 
 +
<source lang="xml">
 +
<?xml version="1.0"?>
 +
<xml-bindings
 +
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
 +
    package-name="examples.virtual">
 +
    <xml-schema namespace="urn:tenant2" element-form-default="QUALIFIED"/>
 +
    <java-types>
 +
        <java-type name="Customer">
 +
            <xml-type prop-order="firstName lastName billingAddress phoneNumber"/>
 +
            <java-attributes>
 +
                <xml-attribute java-attribute="firstName"/>
 +
                <xml-attribute java-attribute="lastName"/>
 +
                <xml-element java-attribute="billingAddress" name="address"/>
 +
                <xml-element
 +
                    java-attribute="phoneNumber"
 +
                    type="examples.virtual.PhoneNumber"/>
 +
            </java-attributes>
 +
        </java-type>
 +
    </java-types>
 +
</xml-bindings>
 +
</source>
 +
 
 +
 
 +
== Creating The Contexts ==  
 +
 
 +
To create a context using multiple bindings files, pass in a list of sources instead of a single source. A source can be a File, a Stream, or a String representing either a URL or a classpath reference. This will demonstrate creating specific contexts for each tenant, using the same set of base bindings in addition to tenant-specific bindings.
  
 
<source lang="java">
 
<source lang="java">
Map<String, Object> properties = new HashMap<String, Object>();
+
Map<String, Object> tenantOneProps = new HashMap<String, Object>();
ArrayList bindings = new ArrayList();
+
ArrayList tenantOneBindings = new ArrayList();
bindings.add("examples/virtual/base-bindings.xml");
+
tenantOneBindings.add("examples/virtual/base-bindings.xml");
bindings.add("examples/virtual/binding-tenant1.xml");
+
tenantOneBindings.add("examples/virtual/binding-tenant1.xml");
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, bindings);
+
tenantOneProps.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, tenantOneBindings);
JAXBContext jc = JAXBContext.newInstance(new Class[] {Customer.class, Address.class}, properties);
+
JAXBContext tentantOneContext = JAXBContext.newInstance(new Class[] {Customer.class, Address.class}, tenantOneProps);
+
 
Marshaller marshaller = jc.createMarshaller();
+
Map<String, Object> tenantTwoProps= new HashMap<String, Object>();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+
ArrayList tenantTwoBindings = new ArrayList();
marshaller.marshal(customer, System.out);
+
tenantTwoBindings.add("examples/virtual/base-bindings.xml");
 +
tenantTwoBindings.add("examples/virtual/binding-tenant2.xml");
 +
tenantTwoProps.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, tenantTwoBindings);
 +
JAXBContext tentantTwoContext = JAXBContext.newInstance(new Class[] {Customer.class, Address.class}, tenantTwoProps);
 
</source>
 
</source>

Latest revision as of 13:48, 16 June 2011

Introduction

EclipseLink MOXy provides the ability to augment the annotation metadata with an XML bindings file. As of version 2.3, EclipseLink MOXy can now process multiple bindings files from different locations, and create a merged set of metadata.

Sample use case:

  1. Initial metadata is specified with a metadata file.
  2. Second version modifies the metadata with an additional XML bindings file.
  3. Subsequent versions continue to modify with additional bindings files.


With the metadata layered in this way a JAXBContext could be created to represent any version of the XML document.

By using this in conjunction with a multi-tenant architecture, you can define a base set of metadata using one XML Bindings file, and then an additional file for each tenant. This example will be based on the object model from the EclipseLink MOXy Extensibile example.


Java Model

ExtensibleBase

package examples.virtual;
 
import java.util.HashMap;
import java.util.Map;
 
import javax.xml.bind.annotation.XmlTransient;
 
import org.eclipse.persistence.oxm.annotations.XmlVirtualAccessMethods;
 
@XmlTransient
@XmlVirtualAccessMethods(setMethod="put")
public class ExtensibleBase {
 
    private Map<String, Object> extensions = new HashMap<String, Object>();
 
    public <T> T get(String property) {
        return (T) extensions.get(property);
    }
 
    public void put(String property, Object value) {
        extensions.put(property, value);
    }
 
}

Customer

The Customer class will be extensible since it inherits from a domain class that has been annotated with @XmlVirtualAccessMethods.

package examples.virtual;
 
public class Customer extends ExtensibleBase {
 
    private String firstName;
    private String lastName;
    private Address billingAddress;
 
    public String getFirstName() {
        return firstName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
 
    public String getLastName() {
        return lastName;
    }
 
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
 
    public Address getBillingAddress() {
        return billingAddress;
    }
 
    public void setBillingAddress(Address billingAddress) {
        this.billingAddress = billingAddress;
    }
 
}

Address

It is not necessary to have every class in your model be extensible. In this example the Address class will not have any virtual properties.

package examples.virtual;
 
public class Address {
 
    private String street;
 
    public String getStreet() {
        return street;
    }
 
    public void setStreet(String street) {
        this.street = street;
    }
 
}

PhoneNumber

Like Customer, PhoneNumber will be an extensible class.

package examples.virtual;
 
public class PhoneNumber extends ExtensibleBase {
 
    private String number;
 
    public String getNumber() {
        return number;
    }
 
    public void setNumber(String number) {
        this.number = number;
    }
 
}


Base XML Bindings

The base XML Bindings file will specify some initial basic metadata that will be used for all tenants.

  • Root Element name for Customer
  • Add XmlValue to PhoneNumber


base-bindings.xml

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="examples.virtual">
    <java-types>
        <java-type name="Customer">
           <xml-root-element name="customer"/>
        </java-type>
        <java-type name="PhoneNumber">
            <java-attributes>
               <xml-value java-attribute="number"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>


Customizations for Tenant 1

The first tenant is an online sporting goods store, that requires the following extensions to their model:

  • Customer ID
  • Customer's middle name
  • Shipping address
  • A collection of contact phone numbers
  • Type of phone number (i.e. home, work, or cell)


The metadata for additional virtual properties is supplied through this tenant's specific EclipseLink XML file.

binding-tenant1.xml

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="examples.virtual">
    <java-types>
        <java-type name="Customer">
            <xml-type prop-order="firstName middleName lastName billingAddress shippingAddress phoneNumbers"/>
            <java-attributes>
                <xml-attribute
                    java-attribute="id"
                    type="java.lang.Integer"/>
                <xml-element
                    java-attribute="middleName"
                    type="java.lang.String"/>
                <xml-element
                    java-attribute="shippingAddress"
                    type="examples.virtual.Address"/>
                <xml-element
                    java-attribute="phoneNumbers"
                    name="phoneNumber"
                    type="examples.virtual.PhoneNumber"
                    container-type="java.util.List"/>
            </java-attributes>
        </java-type>
        <java-type name="PhoneNumber">
            <java-attributes>
                <xml-attribute
                    java-attribute="type"
                    type="java.lang.String"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>


Customizations for Tenant 2

The second tenant is a streaming media provider that offers on-demand movies and music to its subscribers. It requires a different set of extensions to the core model:

  • A single contact phone number


For this tenant we will also leverage an additional mapping file to customize the mapping of the real properties:

binding-tenant2.xml

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="examples.virtual">
    <xml-schema namespace="urn:tenant2" element-form-default="QUALIFIED"/>
    <java-types>
        <java-type name="Customer">
            <xml-type prop-order="firstName lastName billingAddress phoneNumber"/>
            <java-attributes>
                <xml-attribute java-attribute="firstName"/>
                <xml-attribute java-attribute="lastName"/>
                <xml-element java-attribute="billingAddress" name="address"/>
                <xml-element
                    java-attribute="phoneNumber"
                    type="examples.virtual.PhoneNumber"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>


Creating The Contexts

To create a context using multiple bindings files, pass in a list of sources instead of a single source. A source can be a File, a Stream, or a String representing either a URL or a classpath reference. This will demonstrate creating specific contexts for each tenant, using the same set of base bindings in addition to tenant-specific bindings.

Map<String, Object> tenantOneProps = new HashMap<String, Object>();
ArrayList tenantOneBindings = new ArrayList();
tenantOneBindings.add("examples/virtual/base-bindings.xml");
tenantOneBindings.add("examples/virtual/binding-tenant1.xml");
tenantOneProps.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, tenantOneBindings);
JAXBContext tentantOneContext = JAXBContext.newInstance(new Class[] {Customer.class, Address.class}, tenantOneProps);
 
Map<String, Object> tenantTwoProps= new HashMap<String, Object>();
ArrayList tenantTwoBindings = new ArrayList();
tenantTwoBindings.add("examples/virtual/base-bindings.xml");
tenantTwoBindings.add("examples/virtual/binding-tenant2.xml");
tenantTwoProps.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, tenantTwoBindings);
JAXBContext tentantTwoContext = JAXBContext.newInstance(new Class[] {Customer.class, Address.class}, tenantTwoProps);