OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

sdo message

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]


Subject: AW: [sdo] ISSUE 125: Key Property Proposal: Sample Code


Hi Everyone,

Here is some sample code that illustrates the key property functionality, with a resolver. 

public void testXmlRoundtrip() {

   // Define a context defined by introspecting a Java class

   DataObject cal = _helperContext.getDataFactory().create(School.class);

 

   // Create the SDO graph

   cal.set("name","Berkeley");

   DataObject billy = cal.createDataObject("students");

   billy.set("name", "Billy Bear");

   DataObject bob = cal.createDataObject("students");

   bob.set("name", "Bobbie Bear");

   DataObject basketWeaving = cal.createDataObject("courses");

   basketWeaving.set("name", "Basket Weaving");

   DataObject algol = cal.createDataObject("courses");

   algol.set("name", "Algol");

   DataObject revolution = cal.createDataObject("courses");

   revolution.set("name", "Revolution");

 

   // hook things up

   billy.getList("courses").add(basketWeaving);

   billy.getList("courses").add(algol);

   bob.getList("courses").add(basketWeaving);

   bob.getList("courses").add(revolution);

 

   // Create a second context defined by an XSD

   HelperContext hc2 = SapHelperProvider.getNewContext();

   hc2.getXSDHelper().define(getClass().getClassLoader().getResourceAsStream("com/sap/sdo/testcase/internal/pojo/ex/projection.xsd"), null);

 

   // Project from the java context to the XSD context

   DataObject projection = (DataObject)((SapDataFactory)hc2.getDataFactory()).project(cal);

 

   // Produce XML based on the XSD

   String xml = hc2.getXMLHelper().save(projection, "http://projection",    "school");

 

   // I'm imagining here that sending the XML out over the wire (eg, using it as a response to a

   // WebService request. On the client side, we go from the XML back to SDO. We use the context

   // based on the XSD.

   DataObject projection2 = hc2.getXMLHelper().load(xml).getRootObject();

 

   // We can make some changes. We can add a new course...

   projection2.getList("students.0/courses").add("Fortran and You");

 

   // So, now the trip back to the server…

   //I'm skipping the XML step, and simply projecting the modified (XML oriented) data back into

   // my java context

   DataObject cal2 = _helperContext.getDataFactory().project(projection2, new MyResolver());

}

 

 

 

public class DefaultRestoreContext implements Resolver {

   private final Map<Type,Map<Object,DataObject>> _map =

          new HashMap<Type,Map<Object,DataObject>>();

   public DataObject restore(Type type, Object key) {

          Map<Object,DataObject> map = _map.get(type);

          if (map == null) {

                map = new HashMap<Object,DataObject>();

                _map.put(type, map);

          }

          GenericDataObject value = map.get(key);

          if (value == null) {

                value = DataFactory.create(type);

                // I’m imagining a convenience method on type, but this

                // isn’t strictly necessary

                type.setKeyProperties(value, key);

          }

          return value;

    }

}

 

here is the XSD:

 

<?xml version="1.0" encoding="UTF-8"?>

<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://projection" xmlns:tns="http://projection" elementFormDefault="qualified">

    <complexType name="School">

          <sequence>

              <element name="students" type="tns:Student" maxOccurs="unbounded"/>

          </sequence>

          <attribute name="name" type="string"/>

    </complexType>

 

    <complexType name="Student">

          <sequence>

                <element name="courses" type="string" maxOccurs="unbounded"/>

          </sequence>

          <attribute name="name" type="string"/>

    </complexType>

   

    <element name="school" type="tns:School"/>

</schema>

here is Student.java (the annotations are NOT part of the proposal, this is just illustrative... I think the meaning should be clear

@SdoTypeMetaData(uri="http://projection")

public class Student {

   private String _name;

   private List<Course> _courses;

   private School _school;

   @SdoPropertyMetaData(key=true)

   public String getName() {

          return _name;

   }

   public void setName(String name) {

          _name = name;

   }

  

   @SdoPropertyMetaData(opposite="students")

   public School getSchool() {

          return _school;

   }

   public void setSchool(School s) {

          _school = s;

   }

  

   @SdoPropertyMetaData(opposite="students")

   public List<Course> getCourses() {

          return _courses;

   }

   public void setCourses(List<Course> c) {

          _courses = c;

   }

}

and here is Course.java

@SdoTypeMetaData(uri="http://projection")

public class Course {

   private String _name;

   private List<Student> _students;

   private School _school;

  

   @SdoPropertyMetaData(key=true)

   public String getName() {

          return _name;

   }

   public void setName(String name) {

          _name = name;

   }

  

   @SdoPropertyMetaData(opposite="courses")

   public School getSchool() {

          return _school;

   }

   public void setSchool(School s) {

          _school = s;

   }

  

   @SdoPropertyMetaData(opposite="courses")

   public List<Student> getStudents() {

          return _students;

   }

   public void setStudents(List<Student> s) {

          _students = s;

   }

}


I believe that the functionality suggested by the resolver here, namely that within a single project operation a map of objects is maintained can even be the default behavior when no resolver is specified, that is, when the user specifies null instead of giving a resolver object.  That is,

      DataFactory.project(aDataObject, null)

gets a default resolver implement as given, modulus implementation-specific details.  This would be different from

        DataFactory.project(aDataObject)

where no map is being maintained at all (and that is therefore more efficient)

Comments, please.

Ron

 


Von: Barack, Ron [mailto:ron.barack@sap.com]
Gesendet: Dienstag, 3. Juni 2008 11:37
An: Bryan Aupperle; sdo@lists.oasis-open.org
Betreff: AW: [sdo] ISSUE 125: Key Property Proposal

Hi Everyone,
 
There is some special handling associated with compley KeyTypes, or rather with projecting from an "entity" to it a complex key type, which I think should be made explicit.
 
When you project from an entity to a key, you should always create a new instance of the key.  When you modify the value of a key, you are not modifing the value of the corresponding property in the referenced entity, in the "underlying data", you are changing the reference to point to a different entity.  These behaviours are different from the behavior that you get when projecting from one entity to another.  When we project from entity to entity, we get the same number of objects in the target HelperContext that we had in the source HelperContext.
 
I would also like to modify the proposal in the way that the resolver is introduced.  Rather than associating the resolver with the type, I think it's better to have the resolver given as a parameter to the project method.  This means, I guess, introducing a second project method:  the new method takes the resolver as a second parameter.  The resolver interface would also have to take the Type as a parameter
 
       public interface resolver {
            DataObject resolve(Type type, Object key);
       }
 
This works better than doing the association using metadata.  It allows the client to create the resolver himself, and possibly associate it with eg an EntityManager.  If we have the resolver associated with the Type, then the resolver is implicitly "shared" between all threads using the same HelperContext.
 
If there is interest, I'd be happy to show some sample code and demos during todays meeting.
 
Ron
 


Von: Bryan Aupperle [mailto:aupperle@us.ibm.com]
Gesendet: Donnerstag, 29. Mai 2008 17:51
An: sdo@lists.oasis-open.org
Betreff: Re: AW: [sdo] ISSUE 125: Key Property Proposal


Yes that helps

Bryan Aupperle, Ph.D.
STSM, WebSphere Enterprise Platform Software Solution Architect

Research Triangle Park,  NC
+1 919-254-7508 (T/L 444-7508)
Internet Address: aupperle@us.ibm.com



"Barack, Ron" <ron.barack@sap.com>

05/29/2008 10:35 AM

To
Bryan Aupperle/Raleigh/IBM@IBMUS, <sdo@lists.oasis-open.org>
cc
Subject
AW: [sdo] ISSUE 125:  Key Property Proposal





Hi Bryan,
 
The type of the property is still OrderType.
 
It might help to contrast this to the way this XSD would look in SDO 2.1:
 
        <xs:element name="SalesRepType">
             
<xs:complexType>
                     
<xs:sequence>
                             
<xs:element name="name" type="xs:string"/>
                             
<xs:element name="employeeId"
                                 
type="xs:string" sdo:key="true" />
                             
<xs:element name="orders"
                                 
type="xs:anyURI"
                                 
maxOccurs="unbounded"
                                 
sdox:propertyType="tns:OrderType"/>
                     
</xs:sequence>
             
</xs:complexType>
     
</xs:element>
 
When we serialize an object, the values of order are the XPath "address" to the element in the document.  With this proposal, instead of the XPath, we write the key in the XML stream.
 
All that having keys is buying you here is an XML serialization that has some semantic meaning, and therefore is useful to clients
who are not using SDO.  An SDO implementation is still required to resolve the reference during de-serialization.  It's only the format (and contents) of the reference that are being changed.
 
Is that clearer?
 
Ron
 


Von: Bryan Aupperle [mailto:aupperle@us.ibm.com]
Gesendet:
Donnerstag, 29. Mai 2008 16:20
An:
sdo@lists.oasis-open.org
Betreff:
Re: [sdo] ISSUE 125: Key Property Proposal



One additional question -


In SalesRepType you have the property orders, which today is effectively a list of pointers to the actual order data objects.  Does this change with the use of keys?  I.e. would this now be a list of keys which has to be resolved when navigating to the order data objects?  The corresponding XSD suggests this, but it is not clear if that is what you have in mind for the in-memory representation.


Bryan Aupperle, Ph.D.
STSM, WebSphere Enterprise Platform Software Solution Architect

Research Triangle Park,  NC
+1 919-254-7508 (T/L 444-7508)
Internet Address: aupperle@us.ibm.com


"Barack, Ron" <ron.barack@sap.com>

05/22/2008 07:57 AM


To
<sdo@lists.oasis-open.org>
cc
Subject
[sdo] ISSUE 125:  Key Property Proposal







Hi Everyone,

Let me make some proposals regarding keys.  I believe this approach to be consistent with:

Use Cases for Keys and Projection

We begin with a motivating use case.

Domain models tend to be larger and complex than the views used by individual clients.  Moreover, when going from a large server-side model, it is necessary to define the scope of the data which should be transmitted to a remote client.  The boundaries of the data which should be transmitted in a single  packet must somehow be defined.  On the other hand, the door must be left open for clients to further explore the model in succeeding calls to the server.

Imagine a service that returns an Employee object.  In the domain model, Employee has a refence to Department, and Department in turn has a list of all Employees.  If we define the transmission packet to be the transient closure reachable from Employee, then we can never send a single employee, we will always send the complete list of employees in the department.

Our approach is to use keys to represent the boundary points in a transmission packet.  It is assumed that clients that wish to explore the model beyond these boundaries will be able to use the keys to somehow perform lookups, but the API through which this is done is out-of-scope for SDO (being more of a DAS issue).

In the example, we can imagine that the server has a SDO type system in which Employee has a property with type Department.  In the client's type system, however, the corresponding property has type {commonj.sdo}string.  This value would represent the identity of the Department.  The basic functionality we wish to achive  is to allow projection between these two HelperContexts.

Types, Key Properties, and KeyTypes

We need to define the following open content (global) properties.

     sdo:key                    boolean                        (used on properties)
   sdo:keyType                commonj.sdo.Type      (used on types)

   sdo:embeddedKey    boolean                        (used on properties)

The sdo:key property can be set to true on properties under only when isMany=false and either of the following is true

a) the type of the property is a dataType, but not float, double or any other “approximate” type.
b) the type of the property is not a dataType, but itself defines one or more key properties.

A property marked with sdo:key=true is called a key property.

Any type with at least one key property is said to have a key type.  If there is exactly one key property, then if the type of the key property is a dataType, then the key type is the type of the key property.  If there is exactly one key property and the key property is not a dataType, then the key type is the key type of the key property’s type.

 
If a type contains more than one key property then the type must have the sdo:keyType property set.  The value of this property must be a type such that for every key property, the key type also contains a property with the same name.  If the key property is a dataType, then the corresponding property in the keyType must have the same type as the key property.  If the key property is not a dataType, then the type of the corresponding property is the key type associated with the key property’s type.

Example:

OrderType
-- id                   string sdo:key=”true”

-- customer                     CustomerType

-- lineItems                    LineItemType many=”true”

LineItemType
-- order                        OrderType sdo:key=”true” sdo:opposite=”lineItems”

-- lineNumber           int sdo:key=”true”

-- item                 ItemType

LineItemKeyType
-- order                        string

-- lineNumber           int

When the types are defined through XSD, an attribute with type “xs:ID” generates a string property with sdo:key=”true”.

Some DataObjects may wish to use their composite key type directly as a property.  The embeddedKey annotation is used in this case. For instance, LineItemType may also be defined

LineItemType
-- lineItemKey          LineItemKeyType sdo:embeddedKey=”true” containment=”true”

-- item                 ItemType

Sdo:EmbeddedKey cannot be used in combination with sdo:key, and can only be used on containment properties.
Generating XSD from Types using Keys

When generating XSD from an SDO type, non-containment references to keyed types generate elements or attributes whose type correspond to the key type of the referenced object.  If the key type is a dataType and the reference is single-valued, the reference is rendered as attributes.  If the key type is complex, or the reference is multivalued, the reference is rendered as a element.  In either case, the implementation must annotate the attribute or element with “sdox:propertyType”.

For instance, let us extend our previous example, adding SalesRepType, representing the SalesRepresentative that is responsible for the order.  

SalesRepType
-- name                 string
-- employeeId           string, sdo:key=”true”

-- orders                       OrderType, many=”true”, containment=”false”

This generates the following XSD.  

        <xs:element name="SalesRepType">
             
<xs:complexType>
                     
<xs:sequence>
                             
<xs:element name="name" type="xs:string"/>
                             
<xs:element name="employeeId"
                                 
type="xs:string" sdo:key="true" />
                             
<xs:element name="orders"
                                 
type="xs:string"
                                 
maxOccurs="unbounded"
                                 
sdox:propertyType="tns:OrderType"/>
                     
</xs:sequence>
             
</xs:complexType>
     
</xs:element>

If SalesRepType had a multivalued reference to LineItemType instead of a reference to orders, this would look like

        <xs:element name="SalesRepType">
             
<xs:complexType>
                     
<xs:sequence>
                             
<xs:element name="name" type="xs:string"/>
                             
<xs:element name="employeeId"
                                 
type="xs:string" sdo:key="true" />
                             
<xs:element name="lineItems"
                                 
type="tns:LineItemKeyType"
                                 
maxOccurs="unbounded"
                                 
sdox:propertyType="tns:LineItemType"/>
                     
</xs:sequence>
             
</xs:complexType>
     
</xs:element>

If the reference to OrderType was single valued:  

        <xs:element name="SalesRepType">
             
<xs:complexType>
                     
<xs:sequence>
                             
<xs:element name="name" type="xs:string"/>
                             
<xs:element name="employeeId"
                                 
type="xs:string" sdo:key="true" />
                             
<xs:element name="orders"
                                 
type="xs:string"
                                 
maxOccurs="unbounded"
                                 
sdox:propertyType="tns:OrderType"/>
                     
</xs:sequence>
                             
<xs:attribute name="order"
                             
type="xs:string" sdox:propertyType="tns:OrderType"/>
             
</xs:complexType>

                                                                                                         
     
</xs:element>

Question:  How do composite keys affect the XML representation of changeSummary?  For now, I would say we should continue to use only the IDREF or AnyURI representation of references, not the key.  I believe that the DAS group will anyway request fundamental changes to ChangeSummary’s XML, and I wouldn’t want to hold up this proposal waiting for such changes.

Keys and Projection

A type and its keyType are compatible with each other.  This means that a projection may use the keyType directly as a property type.  For instance, we may define a context in which the SalesRepType is defined as

SalesRepType
-- name                 string
-- employeeId           string, sdo:key=”true”

-- orders                       string, many=”true”

Unlike normal projection, when complex DataObjects are projected onto keyType, there is no association that the original object and its projection represent the same underlying data.  For instance, imagine that in one HelperContext, EmployeeType has a reference to DepartmentType, and that DepartmentType has a key type of {commonj.sdo}string.  In another context, instead of the reference to DepartmentType, the corresponding property could have type string.   If we project an instance of EmployeeType into from the first context into the second context, and in the second context change the value of the department property, then this does not indicate that the DepartmentType object in the original context should have the value of its key property changed, rather, that a different department should be referenced.

When projecting from a keyType object to the associated complex data object, the default behavior is to create an object with only key properties filled.  This behavior may be customized by associating a resolver with the type.  We define an interface

        public interface KeyResolver {
             
DataObject resolve(Object key);
          }

and an open content property

            sdo:resolver                Class

This property is meant to be associated with types, and the value of the property must have a no-arg constructor, and must implement KeyResolver.

When projecting from a key object to a DataObject, the system must check if a KeyResolver has been specified for the target type.  If so, the value of the key is passed to an instance of the KeyResolver class, and the returned object is used as the projection of the key.




[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]