[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]
Subject: AW: [sdo] ISSUE 119: Projection and Keys
Hi Everyone,
Moving a discussion from another thread to this thread, for clarity, and so we can remember the issues:
Blaise asked:
* What is the impact of relaxing the SDO name uniqueness requirement on projection?
* What is the impact of SDO-82 on projection?
Right now, the projection algorithm matches by name only. It could be that we need to make this a little more precise when considering that property names may not necessarily be unique, and type names (in the case of XSD anonymous types) may not even be defined. It's also possible that we can say that projection, like static SDO generation, has some additional constraints, such as name uniqueness
These are all valid questions to consider, but what exactly is the relationship with the proposal being discussed here? Does having the compatibility rule regarding keys and entities make the above issues any worse or better?
* Is SDO-119 useful without an identity concept? Currently my thinking is that identity management is required here.
There actually is some identity management within the proposal, the scope in which the identity is meaningful is the graph being projected. SDO doesn't have any sense of a scope that is smaller than the HelperContext yet bigger than a DataGraph. Other frameworks, notably JPA and similar persistence frameworks, do. For example, in JPA, you have the users persistence context, in which the scope of the mapping between objects and identity can be managed on a per-thread basis. In SDO, however, the next larger scope for the identity is the context, and I think we agree that the context can shared between threads, at the enterprise application level. It could be that we need to add something like a persistence context to SDO, but I've been trying to avoid this, and instead to allow the user to inject his own flavor of entity management by specifying an EntityResolver... please see my emails to Bryan in this thread, and my earlier proposals in SDO-125. The current proposal regarding keys and projection is meant to define a default behavior and a baseline on which the future EntityResolver functionality can be built. Would you be more willing to resolve this issue if I added the EntityResolver back in?
* Alignment with SDO-135. I believe the spirit of SDO-119 & projection in general is to enable alignment with other standards. I believe these issues should be worked on in parallel, for example the Binder proposal could be enhanced to unify SDO-135 and projection.
There were some proposals in this direction, which we moved away from based on your previous wish that the functionalities be separated. For the earlier discussion, please see
http://www.oasis-open.org/apps/org/workgroup/sdo/email/archives/200808/msg00001.html
http://www.oasis-open.org/apps/org/workgroup/sdo/email/archives/200807/msg00034.html
The question where I was hanging is whether or not Binder is allowed to wrap the POJO or DOM structure, or must copy involve a copy step. Up to now, we've always though of projection as not requiring a copy step. If we want to bring the concepts together then we must either say Binder allows wrapping, or Projection does not allow wrapping. I'd be willing to further pursue these proposals, but I need some guidence from the TC as to which direction is appropriate. I actually started work on this proposal in 119 once I had the impression that we had a better chance of making progress by separating Binding and Projection. Now the opposite opinion is being expressed. I usually do not propose something without first prototyping, so that it is a significant effort to make a proposal. It is difficult to make progress without stakes in the ground, such as this one, that provide foundations upon which futher proposals can be based.
That said, opinions on wrapping/ copying are more than welcome (but in the appropriate thead, please)
Ron
"Barack, Ron"
<ron.barack@sap.com>
08/15/2008 11:05 AM |
|
I must not have been sufficiently clear about the scenario I am concerned about.
I understand the case where you start with the context with entities and project to the context with keys. The mapping between entities and keys can be created and maintained. I agree there is no problem projecting back tot he context with entities.
Now consider the opposite case. Start with an object containing keys and the mapping between entities and keys has not yet been created (perhaps the object was received via a service call). Now project to a context with entities. Those entities have to be retrieved from the data store. Or am I missing something here?
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>
08/15/2008 09:58 AM |
|
"Barack, Ron"
<ron.barack@sap.com>
08/14/2008 07:20 AM |
|
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).
As an 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.
Keys and Projection
A type and its
keyType are compatible with each other. That mean, an object with a
reference to an entity in one context can be projected onto an object with a
reference to the key type in another context.
We illustrate this with an example.
HelperContext #1
Type Employee
*
property - id (Integer) - KEY
* property - name (String)
* property -
direct-report (List of Employee)
is compatible with the metamodel
HelperContext #2
Type Employee
*
property - id (Integer) - KEY
* property - name (String)
* property -
direct-report (List of Integer)
Here we see the type of the direct-report property has been replaced in the second HelperContext with the corresponding key type.
The projection from an entity to its key has some important semantic differences when compared with projection between entities. Projection between entities creates a new view of the same underlying data. By contrast, a key does not represent a view, but rather a reference to an entity in the underlying data model. When working with different views of the same underlying data, it is natural that changes in one view are reflected in all other views. By contrast, changing the value of a key changes the target of the reference rather than the value of the key property in the referenced data object. When projecting from an entity to a key, a new instance of the key is always created. By contrast, 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.
Conversely, when projecting from a key to an entity then for each distinct key value within the graph being projected, all references to that key must resolve to the same entity.
In many scenarios data will round-trip between contexts, including between contexts in which entity map to keys. Let us consider two context Ce and Ck, representing the entity and the key context, respectively, and a DataObject Oe, in context Ce. Projecting Oe into Ck returns a DataObject, Ok. The transitive closure reachable from Ok is Gk. Every key value in Gk maps to an single entity in Ce, and it is this entity is that is found when Ok (and effective, all of Gk) is projected back into Ce. In cases where the user has set a key property to a value that is not found in Gk, then, as a result of projecting Ok into Ce, a new entity will be created. The created entity has default values for all properties other than the key fields.
We illustrate with an example. Note that the example uses containment relationships in both contexts. This is done for clarity, since it allows an XML representation of the data. The use-case, however, is stronger when the contexts have different (or perhaps no) containment structures. Imagine the following data in HelperContext #1
<employee id="11">
<name>Foo Bar</name>
<direct-report
id="21">
<name>Jane
Doe</name>
</direct-report>
<direct-report id="31">
<name>Jim Jones</name>
</direct-report>
<direct-report
id="22">
<name>John
Smith</name>
</direct-report>
</employee>
After projecting to HelperContext #2, we have
the following data
<employee id="11">
<name>Foo
Bar</name
<direct-report>21</direct-report>
<direct-report>31</direct-report>
<direct-report>22</direct-report>
</employee>
If we imagine the client changes the
list of direct reports, so that the second item in the list has value “41”
instead of “31”, then the meaning of the change is not that the employee with
name “Jim Jones” now has a new ID, but that “Jim Jones” has been replaced by
another employee.
On projecting from context 2 back into context 1, the instance of Employee with id="22" would be detached from the Employee with id="11". Also a new Employee with id="41" would be created and added as a direct report to the Employee with id="11". If the graph in context 1 were in scope of a ChangeSummary, then because the "direct-report" property in context1 is a containment property, the change would be tracked as a delete or a create. If the relationship were non-containment, the change would be tracked as a modification to the employee with id=11, not as a delete to the employee with id=22 or as the creation of a new employee with id=41; semantically, it is only the reference to entity 22 that has changed, the entity itself still exists, and is unaltered. Projecting this data from context 2:
<employee id="11">
<name>Foo Bar</name
<direct-report>21</direct-report>
<direct-report>41</direct-report>
<direct-report>22</direct-report>
</employee>
Into context 1 yields:
<employee
id="11">
<name>Foo Bar</name>
<direct-report id="21">
<name>Jane Doe</name>
</direct-report>
<direct-report
id="41"/>
<direct-report id="22">
<name>John
Smith</name>
</direct-report>
</employee>
Projection between entities and keys becomes more powerful when the relationship through which the entities tie into the graph are non-containment. The following example shows how a complex model that lacks containment relationships can be projected onto a context that requires a specific XML serialization, which implicitly prunes the orignal domain to the requirements of a specific client.
HelperContext #1
Type School
*
property - name (String) - KEY
* property - students (Student) -
many=true
* property - courses (Course) - many=true
Type Student
* property - name (String) - KEY
* property - courses
(Course) - many=true, containment=false, opposite=students
* property -
school (School) - containment=false, opposite=students
Type Course
* property - name (String) -
KEY
* property - students (Students) - many=true, containment=false,
opposite=courses
* property - school (School) - containment=false,
opposite=courses
Notice the m:n relationship between Student and Course. If we imagine a service that should expose this domain model to clients, it is possible that some clients will wish to obtain the list of students participating in a particular course, while other clients may wish to obtain the list of courses in which a particular student is enrolled. The application cannot determine based on the structure of the data which of the two possible containment structures is "correct". Notice also that returning the transitive closure would return all the data associated with the entire school.
In this example the client wants the data
structured according to the following 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>
Notice that we are imposing a containment structure on the original context, as well as pruning it by replacing the course entity by the corresponding key. The following code illustrates the behavior of the project method.
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 = HelperProvider.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 =
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);
// Test that there is one entity per key
value
DataObject billy2 = (DataObject)cal2.getList("students").get(0);
DataObject basketWeavingBill =
(DataObject)billy2.getList("courses")
.get(0);
DataObject bob2 =
(DataObject)cal2.getList("students").get(1);
DataObject
basketWeavingBob = (DataObject)bob2.getList("courses").get(0);
assertSame(basketWeaving2,
basketWeavingBob);
[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]