Hi Blaise,
I'm not sure about whether load should create types.
For the case of XML, I guess we would have to apply something like 9.10, as you
suggest.
In the case of POJOs, I believe that java classes should be
sources of metadata, that is, we need to say that chapter 5 (of the 2.1 spec)
works in both directions. We need a way to trigger the introspection
of classes explicitly through the API, a define(Class) that is equivalent to
XSDHelper.define(Source). This should be the preferred way of
associating types with classes. But I think that we can also trust
the user, and make load(Object), as well as DataFactory.create(Class) and
TypeHelper.getType(Class) trigger the introspection implicitly if the class is
not already associated with a Type.
Ron
Hi Ron,
I like the generic Binder API, I had been thinking
that this would apply nicely to DataObjects as well as XML and POJOs.
My
interpretation of the proposal is that new Types are not created during load
operations. Instead the DataObjects that are created correspond to Types
that already exist within the scope of the HelperContext. If an external
representation cannot be directly linked to a type then an algorithm like
section 9.10 (from SDO 2.1) is used. Is this correct?
With respect
to the uniform handling of different standard representations. I did not
intent to argue that this was a bad thing, only that it is not strictly a
requirement since enough information is available to do specific
bindings.
-Blaise
Barack, Ron wrote:
9279AFBA5302884AB7169C4C51B6FDF70165A8E3@dewdfe1a.wdf.sap.corp
type="cite">
Hi Blaise,
Let's address the fundamental disagreements
first:
1. Can JAXB marshal an arbitrary
POJO?
Actually, I don't know how relevant this discussion is to
SDO, and I don't exactly relish argueing about JAXB with a
member of the expert group, and I want to first of all make clear
that
a) I do not see SDO 3.0 as a means of
fixing any sort of problems or deficiencies in
JAX-B.
b) I do not see SDO 3.0 as
competing in any way with JAX-B
Perhaps my choice of the word "arbitrary" was wrong,
perhaps "unannotated" would have been better. For the record, though, I believe this
is actually listed as a non-goal of JAXB, at least that how I interpret the
statement that "mechanisms to traverse a graph
of JavaBean objects will not be addressed". And of course
there's section 8.2.7, which states that the determination of which
relationships are containment is the responsibility of the programmer,
who must annotate with @XmlID and @XmlIDRef appropriately.
In
any case, since our resolution of SDO-124, I believe SDO 3.0 to be capable of
mashalling an unannotated object graph to
XML.
Staying on the subject of integration with JAXB, the is nothing in
my proposal that would involve the creation of a mapping between all JAXB annotations to SDO
metadata. If we have use-cases
where we need to generate metadata from JAXBs, which I'm not sure we do, but
if, then we would certainly want to use something like
"XSDHelper.define(JAXBContext.generateSchema())", rather than parsing the
annotations ourselves.
2. Is it desireable to handle the different standard
representations (SDO, POJO, JAXB, DOM) uniformly.
I
can't believe you're arguing that this would be a bad thing, the question is,
is the work involved justified by the use-cases. This maybe brings us to
the Binder<T> API. Here is a first pass, simply adding generics to
your API, plus a getHelperContext method.
Generic
Binder
/** * The Binder is used to scope when
a external data representation is linked to a
DataObject. */ public interface Binder<T> {
/**
* Any
DataObjects created will have types that are defined in this
HelperContext.
*/
HelperContext
getHelperContext();
/**
* DataObject customer1DO = binder.load(customer);
* DataObject customer2DO = binder.load(customer);
* customer1DO == customer2DO
*/ DataObject load(T
externalRepresentation);
/** * Object customer1 =
binder.save(customerDO); * Object customer2 =
binder.save(customerDO); * customer1 ==
customer2 */ T
save(DataObject dataObject);
/** * Get the DataObject linked with is
Object. * DataObjects are linked with Objects
through both the load and update operations.
*/ DataObject getDataObject(T
externalRepresentation);
/** * Get the Object linked with is
DataObject. * Objects are linked with DataObjects
through both the load and update operations.
*/ T getExternalRepresentation(DataObject
dataObject);
/** * Use
this method if you want the changes made to the Object to be reflected in the
corresponding DataObject. */
DataObject updateDataObject(T
externalRepresentation);
/** * Use this method if you want the changes made
to the DataObject to be reflected in the corresponding
Object. */ T
updateExternalRepresentation(DataObject
dataObject);
}
The next question is, how do you get a
Binder: my first idea would be through
interface HelperContext
{
...
<T> Binder<T>
createBinder<Class<T>
representationClass);
...
}
Where this would be required to return binders
for org.w3c.dom.Node, for java.lang.Object (POJOs) and for
commonj.sdo.DataObject (in this case, the functionality would be "projection",
maybe we would remove projection and replace it with this functionality.
I'm still doing some evaluation of this approach, but I want to throw it out
there to see if you think it is something to which you could potentially
agree.
Best Regards,
Ron
Hi
Ron,
I see that there are fundamental areas in which we disagree:
- <Ron>One reason
is that I can't use the JAXB marshaller on an arbitrary POJO, because
the arbitrary POJO will have non-containment references that are not
annotated with @IDREF.
</Ron>
From the Oracle
perspective you can use JAXB to marshal an arbitrary POJO, that is one of
its primary goals. If the default rules are not sufficient then you
customize the binding through the use of annotations until the XML
representation truly reflects the data. Implementations such as
TopLink/EclipseLink even improve upon this functionality. SDOs are
meant to be an alternative SCA paramater type specifically designed for use
in a disconnected environment.
- <Ron>In my SOA infrastructure, it's pretty desireable
to handle these different representations uniformly.
</Ron>
SCA
components know their parameter types, and therefore can easily know the
appropriate binding mechanism (JAXB, SDO, XML). I don't see a strong
case for having a uniform API, or the need to convert everything to
DataObjects internally.
<Ron>It's not a small undertaking like Mt
Everest isn't a small hill.</Ron> I'm
not against hard work, but if I interpret your proposal correctly the work
would involve the creation of a mapping between all JAXB annotations to SDO
metadata. The proposal may also include the creation of a mapping
between all JPA annotations (including XML metadata) to SDO metadata.
The view from Mt Everest may be better than the view from the hill, but
building my house on the hill made the commute to work much easier
;).
<Ron>I'm try to understand why we need PojoHelper in
addition to
PojoBinder. POJOHelper
creates DataObjects from POJOs, and is required just like XMLHelper to ensure
that all the relationships are preserved during the load/save process.
In other words it should ensure the following is true. customerPojo ==
customerPojo.getOrders().get(23).getCustomer() DataObject
customerDataObject =
PojoHelper.INSTANCE.load(customerPojo) customerDataObject ==
customerDataObject.getList("orders").get(23).get("customer")
Note
that if POJOHelper was used a second time to create DataObjects from POJOs the
DataObjects would not be identical to the DataObjects created the first
time: DataObject
customerDataObject2ndConversion =
PojoHelper.INSTANCE.load(customerPojo) customerDataObject != customerDataObject2ndConversion
This
is where POJOBinder comes into play. POJOBinder forms a link between the
POJO and the DataObject. With this link formed you can make changes on
one side and then apply them to the other side. POJOBinder
pojoBinder = PojoHelper.INSTANCE.createPOJOBinder(); DataObject
customerDataObject = pojoBinder.load(customerPojo) customerDataObject ==
customerDataObject.getList("orders").get(23).get("customer") DataObject
customerDataObject2ndConversion =
pojoBinder.load(customerPojo) customerDataObject == customerDataObject2ndConversion
<Ron>Sorry, I don't get your point
here. Are you
saying that the persistent
objects are disconnected before handed to
the PojoHelper</Ron> My
intention here is to have SDO work with JPA as well as possible. In
areas like converting objects that are JPA entities with lazy loading to SDOs
the default conversion may involve triggering the lazy relationships.
Currently the serialization of JPA entities with JAXB causes this. If we
want to do better I would rather petition the JPA group (a number of SDO 3.0
members have JPA spec group contacts) for standard hooks than introducing too
many SDO tricks to hack this in.
<Ron>What worries me
more about the approach is the potential side effects (e.g., modifying
the POJO would cause DataObject.get() to return the new values, and
vice-versa). But this seems to be
something we can document, make our users aware of, and even sell as a
"feature, not a
bug".</Ron> One
of the fundamental decisions to be made is if modifying the POJO directly
affects the DataObject, and if modifying the DataObject directly affects the
POJO. Although it is easy for SDO to push all changes to the POJO level,
it is not possible (without something like byte code manipulation) to have ALL
changes made to the POJO model immediately reflected in the corresponding
DataObjects (although it is possible to reflect SOME changes).
<Ron>Are you saying
that you are no longer interested in introspecting POJOs as a source of
metadata?</Ron> I
think the sources of metadata will become clearer once other issues have been
decided on. This is an area where compromise is possible.
<Ron>You mean public <T> Binder<T>
createBinder(Class<T> dataRepresentation), right? This is probably
an API we could work on to get the uniformity wrt standard
representations that I want, without requiring that the entire
HelperContext be re-implemented for every such representation (which you
mention below as an objection to the HelperContext<Object>
approach). The idea would be to move "project" from DataFactory to
Binder<DataObject>...and rename it to load, or load to project, or
whatever. Potential for compromise here, I hope. Let me work on
the API and see how it could fit in
to our infrastructure.
</Ron> We'll
discuss the API proposal when it is
available.
-Blaise
Barack, Ron wrote:
9279AFBA5302884AB7169C4C51B6FDF701622F70@dewdfe1a.wdf.sap.corp
type="cite">
Hi Blaise,
SDO 3
is finally getting fun. I've been thinking about your ealier
question
Why do (in the future):
HelperProvider.getPojoContext().getXMLHelper().save(pojo); When you can
do (today):
JAXBContext.newInstance().createMarshaller().marshal(pojo);
One reason is that I can't use the JAXB marshaller on
an arbitrary POJO, because the arbitrary POJO will have non-containment
references that are not annotated with @IDREF. Now that SDO
3.0 can serialize to non-closed graphs (via orphan properties) I have reason
to prefer SDO's marshaller (in some cases... esp, where XML
fidelity does not matter).
Another reason is
because I cannot say JAXBContext.newInstance().createMarshaller().marshal(DataObject)
or
JAXBContext.newInstance().createMarshaller().marshal(DOMNode) or
JAXBContext.newInstance().createMarshaller().marshal(whatever-other-structure-for-which-I-can-have-a-binder).
In my SOA infrastructure, it's
pretty desireable to handle these different representations uniformly.
Of course, this functionality is really also just a convenience
function. Internally, the different structures would be converted to
DataObjects.
more comments
inline...
Ron
PS: Does everyone's
mail client handle the different fonts that I am using to keep my voice
seperate from Blaise's? It seems like Frank's client converts
everything to plain text... Is it OK to continue the discussion
in this
mode?
Hi Ron,
The POJOHelper proposal is
focussed on POJO-to-SDO mapping rather than deriving SDO types from JPA
and/or JAXB annotations (the latter is not a small undertaking).
It's not a small undertaking like Mt Everest isn't
a small hill. What do you think about the idea of deriving types
from JAXB by using something like
XSDHelper.define(JAXBContext.generateSchema())? I know real code would
be more complex, but as pseudocode you get the idea. Of course, if the
JAXBs were generated from an XSD, it would be much, much better to have the
XSD available as a direct source of metadata, and I think we should
encourage this. But in cases where the XSD is not available, this is
the best we can do, I guess.
Yes the following
would be expected to work using POJOHelper: customerPojo ==
customerPojo.getOrders().get(23).getCustomer() DataObject
customerDataObject =
PojoHelper.INSTANCE.load(customerPojo) customerDataObject ==
customerDataObject.getList("orders").get(23).get("customer") I'm try to understand why we
need PojoHelper in addition to PojoBinder. In order to implement the
hooking up of non-containment references you need to maintain a map from the
POJO to the corresponding SDO. This is the functionality that the
PojoBinder provides. It seems like PojoHelper would be
implemented by creating a binder, doing the conversion, and then throwing
the binder away. That is, PojoHelper is simply a convenience
function; the real work is done by PojoBinder. I'm not saying it's
not a desireable convenience function, but we should focus first on the
methods/ interfaces that do the real
work.
When creating SDOs from POJOs
that happen to be JPA entities, it is important to consider the lazy loading
aspect. Until (if ever) JPA offers a means to introspect if a
relationship has not been realized then it will be difficult for SDO
implementations working against standard JPA to accomplish this, although
vendors offering both SDO & JPA implementations can do this in a
proprietary way. Sorry, I don't get your point
here. Are you
saying that the persistent
objects are disconnected before handed to
the PojoHelper ? ---
I
do see the POJO to SDO step as a copy rather than a wrap operation.
This is do to the disconnected nature of SDO.
I would like to
consider relaxing the "disconnected nature of SDO" in some cases, but it's
really not necessary, here. It is the POJOs that are (potentially)
connected.
Wrap Approach
While the wrap approach
does have the advantage of not requiring a copy step, a mechanism will need
to be provided to deal with how to re-sync the DataObject with the POJO
(after serialization).
POJO --WRAP-STEP-->
DataObject(WRAPPING POJO) --SERIALIZE--> XML --DE-SERIALIZE-->
DataObject(WITHOUT POJO)
there's no reason why
the story has to stop here. Whether or not the DataObject is a wrapper
or uses some other structure to hold values, the PojoBinder (or
HelperContext<Object>.getDataFactory()!) would still be in
the capable of converting from the DataObject to a POJO.
It's just that, if it is a wrapper, then obviously we can convert to POJO
very quickly, easilly, and with a very small memory footprint. The
wrapper approach is simply a performance optimization, it doesn't really add
or remove functionality...wrapping is allowed, but never required. If
we imagine BusinessProcess, Rules, and Mapping engines that are all
implemented using SDO, then the
chain
POJO --WRAP-STEP-->
DataObject(WRAPPING POJO) -- SDO-based component --
DataObject(Wrapping POJO, Modified) -- UNWRAP --
POJO
Is
something that will meet my KPIs, where as a copy step may be too
expensive.
What worries me more about the approach is the
potential side effects (e.g., modifying the POJO would cause
DataObject.get() to return the new values, and
vice-versa). But this seems to
be something we can document, make our users aware of, and even sell as
a "feature, not a
bug".
Copy Approach
Here is how the copy approach can be used
in a disconnected scenario:
Step #1 - Retrieve SDO Information From
Server Database --JPA--> POJO --POJOHelper--> DataObject
--SERIALIZE--> XML
Step #2 - Receive SDO on Client Modify SDO and Return to
Server XML --DE-SERIALIZE--> DataObject --MODIFY-->
DataObject(MODIFIED)
Step #3 -
Receive SDO on Server XML --DE-SERIALIZE-->
DataObject(MODIFIED) --POJOHelper--> POJO' --JPA-MERGE--> POJO
--JPA--> Database
as I said, this works
for an implementation that allows wrapping just as for an implementation
that has a copy step. No difference
here.
---
Question #1 -
To what does XMLBinder
bind?
Your assumptions are
correct:
- XMLBinder would bind DataObjects to DOM nodes, although like JAXB we
could offer XMLBinder<XmlNode> instead.
- XMLHelper would have a method called createXMLBinder() and/or public
<T> createBinder(java.lang.Class<T> domType)
You mean public <T> Binder<T>
createBinder(Class<T> dataRepresentation), right? This is
probably an API we could work on to get the uniformity wrt
standard representations that I want, without requiring that the entire
HelperContext be re-implemented for every such representation (which
you mention below as an objection to the HelperContext<Object>
approach). The idea would be to move "project" from DataFactory to
Binder<DataObject>...and rename it to load, or load to project,
or whatever. Potential for compromise here, I hope. Let me work
on the API and see how it could fit in
to our infrastructure.
---
Question #2 - What is the
type of the DataObject that is created through PojoHelper.load()?
The mapping between
DataObjects and POJOs is defined much like the mapping between DataObjects
and XML, through setting properties on Type & Property or through
annotations on the XML schema. The mapping is established on the SDO
side not the POJO side.
Are you
saying that you are no longer interested in introspecting POJOs as
a source of
metadata?
---
Question #3 - If a PojoHelper is being used to translate to and from
JAXBs, doesn't it need a handle to the JAXB
context?
The POJO helper is used to
translate to/from POJOs and not JAXB objects. Therefore only a
SDO-to-Object mapping is required on the already defined types and would not
require a JAXB context.
As you mention you could sync between JAXB
and SDO through the use of an XML binder on each side. The purpose of
POJOHelper however is to expose any object so that it can traverse an SCA
system as a DataObject, and then be returned to object form to work with
things like JPA.
---
Difference Between POJOHelper &
POJOContext?
I think the
difference between these two concepts is quite large. POJOContext
requires all the helpers to work with POJOs, while POJOHelper focuses
specifically on converting DataObjects to POJOs. This matches what we
did with XML, we have an XMLHelper and not an XMLContext.
I understand, but
I see the Helpers mostly as simple convenience functions over an
internal XX-to-DataObject
adaptation.
SCA implementations already
need to address SDOs and POJOs as parameters. I don't see having one
API to handle everything being necessary, especially in terms of XML
handling the SDO API still has a ways to go to catch
JAXB.
Projection is not the
only means of moving data across the wire. In SDO projection can be
leveraged when appropriate, but in a typical disconnected environment a
solution is requirement that survives serialization (see the Copy Approach
example above). As I wrote
above, I don't see the problem
here.
-Blaise
Barack,
Ron wrote:
9279AFBA5302884AB7169C4C51B6FDF7016228ED@dewdfe1a.wdf.sap.corp
type="cite">
Hi Blaise, Rick,
Some additional questions and
comments...
If I assume a bunch of POJOs that
are connected in a net, with cycles, etc, like POJOs tend to be
connected, and I say, for instance, that
customerPojo ==
customerPojo.getOrders().get(23).getCustomer()
And then I create a SDO by loading from the
PojoHelper
DataObject customerDataObject
= PojoHelper.INSTANCE.load(customerPojo)
Then I would expect
customerDataObject ==
customerDataObject.getList("orders").get(23).get("customer")
Is that the way you expect things to work even
when using the PojoHelper instead of the PojoBinder? I'm asking
because this behaviour implies that at least during the creation of the
data objects, some sort of binder was there, maintaining the map of POJO
objects we've already seen and the associated DataObjects. It's true
that the binder could have been thrown away after the call to
PojoHelper.load has finished, but this then precludes the possibility that
the conversion from POJO to DataObject occurs lazilly... it means that
that PojoHelper.load must translate the entire transitive closure in a
single call. I my opinion, in order to handle integration with
JPA, it's important that at least non-containment references be traversed
lazilly.
The other question I have concerns a possible
semantic difference between the HelperContext<Object> and the
PojoHelper approaches. When I think of converting a Pojo to a
DataObject using the project method, I'm thinking that the DataObject
would in fact be a wrapper around the Pojo, the Pojo would (or at least
could) be the "underlying data store" we talk about when discussing
SDO-66. Is this how you imagine PojoHelper/Binder working, or do you
envision a copy step occuring during the translation?
Best Regards, Ron
Hi Blaise,
I'm encouraged by the agreement on semantics.
We all seem to agree
1) That we need to round trip between POJO and
DataObject "views" of the data.
2) That we need to maintain object identity
between the different views, that is, we need the
binder.
First question: to what does XMLBinder
bind? Am I correct in assuming DOM nodes? And that XMLHelper
would get the method createXmlBinder?
Second question: what is the type of the
DataObject that is created through PojoHelper.load()? Are you
assuming that the class is introspected, and used to derive an SDO
type? Do we need PojoHelper.define(Class)?
I hope I did not give the impression that I want to
reinvent the wheel or compete in any way with JAXB. For all the
reasons that you list, that is out of the question for SDO. We want
to integrate with JAXB. And, at least as important, we want to
integrate with JPA. When it comes to deriving SDO types through
introspection, we have a disconnect here. One problem
we have is that the natural interpretation of a POJO in JPA is that
relationships are non-containment (unless they are marked as embedded),
whereas the interpretation of an unannotated POJO in JAXB would be that
there is a containment relationship. Another problem that we face is
that JAXB (since it has such good schema coverage) is very complex indeed,
with getter methods returning JAXBElements, DOM nodes, or simple values
depending on the details of the schema and XML. Going from JPA to
SDO is compatitively straightforward. This seems
to lead to the idea that we need to support seperate strategies, that
is, we need a JaxB PojoHelper and a plain/JPA PojoHelper. Both could
have the same interface, they would just have different implementations
(especially for "define").
Third question: If a PojoHelper is being used
to translate to and from JAXBs, doesn't it need a handle to the JAXB
context? So the API to get a JAXB helper would be something
like
PojoHelper
HelperContext.getPojoHelper(JAXBContext)
Actually, I've spent a lot of time thinking about how
to do a robust integration between JAXB and SDO (simple cases are simple,
but complex cases are very hard), and I've come to the conclusion that
it's best to go over DOM nodes, with "binders" on each side. Do you
agree? If so, do we really need a PojoHelper for JAXB integration,
isn't what you call the XMLBinder enough? (If only the RI/ JSE 6
versions fully implemented this functionality...BTW is eclipseLink better
in this regard?).
I think once we get these small
points settled, the differences between having a
PojoHelper and a PojoHelperContext will be pretty small, as far
as the functionality that they offer. The difference is mostly in
the preferred style of the API. I can see where you'd say that
HelperContext<Object> is a "heavy" solution to the problem. On
the other hand, for the SCA use case, it's pretty liberating to be able to
say that I have a HelperContext on both sides of the wire. It could
be a HelperContext<Object>, or a HelperContext<DataObject>,
but in any case, when moving data over the wire, all I do is project from
one context into the other. I could achive the same thing with
PojoHelper, it would just take alot more code and configuration. In
this case, HelperContext<Object> has clear
advantages.
What are the use cases where PojoHelper is
"lighter"?
Best Regards,
Ron
Hello All,
The introduction of a
POJOHelperContext is quite a heavy weight solution to this problem.
Why do (in the future):
HelperProvider.getPojoContext().getXMLHelper().save(pojo); When you can
do (today):
JAXBContext.newInstance().createMarshaller().marshal(pojo);
JAXB
2.0 already has the following over SDO:
- JAXB 2.0 is already included in Java SE 6.
- Marshaller & Unmarshaller are a richer API than SDO's
XMLHelper.
- Supports 100% of XML schema concepts
- Integrates with Java EE standards such as JAX-WS (including support
for binary attachments)
- Well defined name mangling algorithm, meaning portability across
vendors.
Instead of re-inventing the wheel, we can deal
specifically with converting POJOs to/from DataObjects. My proposal
is that we address this much like we handled converting XML to/from
DataObjects by creating a new POJOHelper (see interface below). If
you intend on working with both the POJOs and DataObjects and want to to
update the other accordingly then I propose introducing a new class called
POJOBinder (see interface below). POJOBinder maintains a link
between the POJO and the corresponding DataObject and allows you to apply
the changes from one to the other.
JAXB 2.0 has a similar concept
called XMLBinder. It was introduced in JAXB to address XML fidelity
issues. In addition I propose adding a XMLBinder to XMLHelper, (in a
manner similar to POJOBinder & POJOHelper). This can be used to
address many (if not all) of the SDO XML fidelity
issues.
POJO Helper
/** * POJOHelper is
a mechanism to convert DataObjects to/from POJOs. *
DataObjects are linked to the corresponding POJOs by specifying a property
(to be defined) on a Type, * or through an annotation (to be
defined) in the XML schema. */ public interface POJOHelper
{
/** * DataObject
customer1DO =
POJOHelper.INSTANCE.load(customer); *
DataObject customer2DO =
POJOHelper.INSTANCE.load(customer); *
customer1DO != customer2DO
*/ DataObject load(Object
object);
/** *
Object customer1 =
POJOHelper.INSTANCE.save(customerDO); * Object
customer2 =
POJOHelper.INSTANCE.save(customerDO); *
customer1 != customer2
*/ Object save(DataObject
dataObject);
POJOBinder
createPOJOBinder();
}
POJO
Binder
/** * The POJOBinder is used to scope when a
POJO is linked to a DataObject. * The Binder concept could easily
be applied to XMLHelper to address many (if not all) * of the XML
fidelity issues. */ public interface POJOBinder
{
/** * POJOBinder
pojoBinder =
POJOHelper.INSTANCE.createPOJOBinder(); *
DataObject customer1DO =
pojoBinder.load(customer); * DataObject
customer2DO = pojoBinder.load(customer); *
customer1DO == customer2DO
*/ DataObject load(Object
object);
/** *
POJOBinder pojoBinder =
POJOHelper.INSTANCE.createPOJOBinder(); *
Object customer1 =
pojoBinder.save(customerDO); * Object
customer2 = pojoBinder.save(customerDO); *
customer1 == customer2
*/ Object save(DataObject
dataObject);
/** *
Get the DataObject linked with is Object. *
DataObjects are linked with Objects through both the load and update
operations. */
DataObject getDataObject(Object object);
/** * Get the Object linked with is
DataObject. * Objects are linked with
DataObjects through both the load and update
operations. */ Object
getPOJO(DataObject);
/** * Use this method if you want the changes
made to the Object to be reflected in the corresponding
DataObject. */
DataObject updateDataObject(Object object);
/** * Use this method if you want the changes
made to the DataObject to be reflected in the corresponding
Object. */ Object
updatePOJO(DataObject
dataObject);
}
-Blaise
Barack, Ron wrote:
9279AFBA5302884AB7169C4C51B6FDF7015A4A43@dewdfe1a.wdf.sap.corp
type="cite">Hi Frank,
We agree on the main point, which is that projection should be possible in both directions. Do you also agree to the semantics, that calling
helperContext.project(pojo) always returns the same DataObject, and that calling (in your API) dataObject.project(Pojo.class) always returns the same object? That is, whatever the API, in this sense projecting to and from the POJO world works just like projecting between SDO contexts?
Putting all POJOs in a virtual HelperContext gives you two things:
1. It allows you to determine the rules of the projection. For instance, we could have a JaxBHelperContext that projects to JaxB using a different algorithm than is normally used to project to POJOs. (Note: JaxB classes are not necessarily annotated).
2. It gives you a place to manage the mapping between POJOs and DataObjects. Otherwise, the only way I can think of managing the association is by using weak hash maps. Maybe there's nothing wrong with managing such an association through weak hash maps...that's what hash maps were invented for. But it seems like a poor design to me.
Maybe we should start talking use-cases. As usual, I'm thinking about local wires in an SCA composite. I'm thinking about a SOA landscape where some components are written in Java and use POJO data objects, there is some kind of XML based process engine (say BPEL), and some components are written using SDO data objects. Maybe there are some components that are also DOM based. Anyway, we don't want to say that in order to attach your application into the landscape you have to write it so that it uses static SDOs. This would mean that every "new" has to be replaces with a DataFactory.create().
We've established HelperContext.project as the way to move data between two SDO based applications. That is, each application has ist own HelperContext, and we project the data representation from one to the other. The question is, why should it be different when an application uses POJOs? By having POJO helper contexts I can say that each application has it's own HelperContext. Even the POJO application has a HelperContext, just a HelperContext<Object> instead of a HelperContext<DataObject>. But the way to move data between them is consistent, through HelperContext.project.
Plus the idea of taking a POJO and calling HelperProvider.getPojoContext().getXMLHelper().save(pojo) is just really cool. ;-)
Best Regards,
Ron
-----Ursprüngliche Nachricht-----
Von: Frank Budinsky [mailto:frankb@ca.ibm.com]
Gesendet: Donnerstag, 3. Juli 2008 23:58
An: sdo@lists.oasis-open.org
Betreff: Re: [sdo] Re: ISSUE 130: New DataObject method: cast()
Hi Ron,
Thanks for your reply ... some interesting ideas.
As you may have guessed, I'm very much in favor of changing the argument
of HelperContext.project() to Object and using it as the API to convert
from POJO to DataObject.
I'm not so sure, however, about using HelperContext.project() as the API
to go from DataObject to POJO. I've given it quite a bit of thought and I
can't convince myself that it's the right way to handle this. In my mind,
it seems too complex to try to think of every Java Object as being in an
SDO context. It seems simpler to me to think of a POJO as being in "no
context", but by using HelperContext.project(), you can "bring it into a
context" and then work with it as a DataObject.
Your generic POJO HelperContext, below, helps to highlight what I mean:
HelperContext<Object> getPojoContext();
As you've realized, the only class that can be used for the generic
HelperContext argument is java.lang.Object, since it's the only base class
for any arbitrary POJO class (e.g., Company, Employee, Department, etc.).
Given this, it seems quite odd to think that any java class is
conceptually in the "Object" context - for example, java.lang.Integer
would fall into this category. Given that the generic POJO context is
really only capable of working with "proper SDO-capable objects", the
various SDO helper methods, e.g., XMLHelper.save(), CopyHelper.copy(),
would need to fail, if the Object passed in isn't really an SDO-capable
object. If instead, we said that POJOs are in no context, but you can
project() them into a context if you want to use them with SDO helpers,
then the only possible failure would be if
HelperContext.project(someObject) fails. For example
someContext.project(new Integer()) would probably fail - because it's not
really a SDO-capable POJO. On the other hand, someContext.project(new
Company()) would probably succeed. Once you have the DataObject in the
target context, you can then use SDO helpers, e.g., CopyHelper, XMLHelper,
and know that they will work.
Whether or not we can convince ourselves that HelperContext.projsec() is a
good way to convert an SDO to a POJO, it seems that it still isn't as user
friendly as the API I've proposed. It would still require a Java cast:
Company company =
(Company)HelperProvider.getPojoContext().project(myDataObject);
I would think that the DataObject method I suggested would still be a
cleaner API:
Company company = myDataObject.cast(Company.class);
Even if, the implementation of this method would simply delegate to a POJO
context (although, as I said above, I'm not sure that's the right way to
do it anyway).
This discussion, has however, made me start to think that the
DataObject.cast() method I've proposed would be better named
DataObject.project(), for consistency with HelperContext.project() which I
think is the right API for the reverse operation.
I hope my thoughts are clear enough here. This is a fairly complicated
topic to discuss in email.
Thanks,
Frank
"Barack, Ron" <ron.barack@sap.com>
07/01/2008 04:38 AM
To
Frank Budinsky/Toronto/IBM@IBMCA, <sdo@lists.oasis-open.org>
cc
Subject
[sdo] Re: ISSUE 130: New DataObject method: cast()
Hi Frank,
As you point out, for the case of getSequence() there is no loss of
functionality here. Not so wrt casting between DataObject and a static
SDO. In this case, we would be taking a functionality that allows
"conversion" in both directions with a functionality that allows
"conversion" in only one direction. I don't think we should consider a
resolution of the issue that leaves SDO 3.0 weaker than SDO 2.1, and then
hope that the missing functionality is added back in through the
resolution of a seperate issue.
One of the selling points of SDO is that clients can use the (type safe,
business logic oriented) static SDO to make changes, and then send the
modified data, complete with change summary back to the server. The
server can then use the ChangeSummary, rich metadata model, XML
serialization and other functionality provided by the SDO infrastructure.
In order to make this work in any sort of reasonable way, we need to
maintain the association between the static SDOs and the corresponding
DataObjects so that identity is maintained. When we return the DataObject
that corresponds to a particular POJO, we must always return the same
DataObject. (Note here the correspondence with the behavior when
projecting between contexts...this supports the ideas that I will be
proposing later in this email.) In SDO 2.1, association between the
static SDO and the DataObject is maintained because the instance
implements both. Potentially, we could weaken this to requiring that the
association be maintained through references (that is, that the POJO could
have a reference to the corresponding DataObject). This doesn't help us
when dealing with POJOs that are not "SDO-ready", that is, that are simple
JavaBean data containers that are neither castable nor contain references
to DataObject. In this case, the association must be maintained
externally. The only way I can think of doing this is to have some sort
of (weak) map from the POJO to the DataObject. Of course, maintaining
such a map introduces its own set of problems and costs, made more
critical because the conversion between POJO and DataObject is probably
something we want to do lazilly. Clients that are in the position to work
with static SDO should continue to work just as efficiently as before.
Therefore, I wouldn't want to see the new functionality, the ability to
move between POJO (and potentially also DOM) data representations and
DataObjects, as a replacement for static SDO. We are talking about a new
functionality here: converting from a POJO (or other) data representation
to DataObject and back.
The most obvious API for converting from a POJO object to an SDO is to
reuse the project method from SDO-66. That is, to change the signature
from project(commonj.sdo.DataObject) to project(java.lang.Object). The
behavior is simply to consider the POJO object as if it were a static SDO.
This is the key idea behind everything I will propose here. Of course,
to make this work we need something like what I proposed in SDO-5, a way
to introspect the classes and generate an SDO metamodel. If we have that,
then we can consider every POJO object a potential SDO. That is, the POJO
behaves exactly like the DataObject for which it could be the static
representation.
If we are going to consider the POJOs "potential" DataObjects, then I
think it follows to consider them to be defined in some HelperContext. If
there is a HelperContext that manages the POJOs the way that normal
HelperContexts manage DataObjects, then to get from a DataObject to a POJO
is simply a matter of projecting from the DataObject into the POJO
context.
I think the approach could be just as extensible as the proposed cast
method. For instance, we could have a DOM context. Projecting into this
context returns a Node.
The approach also give the user the chance to control the POJO ->
DataObject map, in that he can control the HelperContext that maintains
it. In a way, the helperContext works like the JaxB Binder.
Users could obtain a POJO helper context from the HelperProvider.
Something like: HelperProvider.getPojoContext(ClassLoader). The user
could then define types in this context using the API proposed in SDO-5.
Alternatively, we could be a bit more JAX-B like, and have
HelperProvider.getPojoContext(Class ...) or
HelperProvider.getPojoContext(Package).
What about the behavior of the Helpers within the HelperContext?
Logically, the behavior of CopyHelper, EqualityHelper, even XMLHelper are
all clear from the concept stated above, the POJOs behave just like static
SDOs. The APIs, however, don't match... Everywhere where
commonj.sdo.DataObject appears the API becomes unusable. Here is a place
where Generics could be used. We could make all our Helpers generic, eg,
XMLHelper<T> {
...
String save(T dataObject, String uri, String localName);
...
}
We would then have
HelperProvider {
HelperContext<DataObject> getDefaultContext();
HelperContext<Object> getPojoContext();
<T> HelperContext<T> getOtherContext(Class<T> t); // Probably
Node
...
}
I think this approach has a lot of potential. It would be pretty neat to
be able to e.g. serialize POJOs to XML using the SDO rules (including
orphan properties, etc). Normally, I have a working prototype before I
make a proposal like this. In this case, I'd like to get a little
feedback from the group first. We don't have to go all the way to
accepting the API changes to make this all work, in fact, I'd rather leave
the API changes to a general refactoring of the API (for which we have an
entire scope item).
What do you think?
Ron
-----Ursprüngliche Nachricht-----
Von: Frank Budinsky [mailto:frankb@ca.ibm.com]
Gesendet: Freitag, 13. Juni 2008 20:43
An: sdo@lists.oasis-open.org
Betreff: [sdo] Re: ISSUE 130: New DataObject method: cast()
Hi Ron,
Sorry I didn't provide the problem statement. This is what I had in mind:
<BEGIN DESCRIPTION>
An SDO Data Object is a data structure composed of named properties. The
DataObject interface provides the primary standard Dynamic API for reading
and manipulating the underlying data structure. However, a number of other
interfaces provide alternate "views" of the same data structure:
1) Sequence.class - if the object's type isSequenced
2) a custom Java interface (e.g., Company.class) - if the type is static
SDO
Another possible view of a data object (currently
implementation-dependent, but a possible future addition to the spec)
would be a DOM view:
3) Node.class - if one wants to provide a 100% XML fidelity view of the
underlying XML structure using an XML standard API
The current approach for accessing alternate views is using specific APIs
for each view:
1) DataObject.getSequence() to get the Sequence view
2) Java cast - e.g., (Company)myDO - for a static SDO view
3) If we want to get a Node view, then we'll need to add some new API for
that - e.g., XMLHelper.getNode(myDO)
This proposal suggests to instead provide a single uniform API for
accessing any alternate view. This will have the advantage of simplicity
(1 method for all) as well as extensibility for future supported (or even
implementation dependent) views.
<END DESCRIPTION>
Now, to answer your questions (from below) Ron:
1) I'm not sure if we need to cast back from every possible view - if so,
then we may want to add one or more APIs for that as well, but I think
it's a separate issue. Note that Sequence currently doesn't provide a
method to get back to the DataObject view - i.e., there is no
Sequence.getDataObject() method.
2) I'm just saying this will "probably" be useful when we want to
integrate with JAXB/JPA. It opens up the possibility of implementations
supporting static using DataObject proxies, or similar, instead of
byte-code insertion or specialized code generation to make sure that
everything is done in a single instance.
3) JAXB is a static solution. If we want Dynamic SDO with 100% XML
fidelity, we need something like Node. Note that I said "something like" -
I'm open to other suggestions, but I think that since Node is "the
standard XML API", we should consider using it.
I hope this helps to clarify things.
Thanks,
Frank.
"Barack, Ron" <ron.barack@sap.com>
06/12/2008 09:36 AM
To
Frank Budinsky/Toronto/IBM@IBMCA, <sdo@lists.oasis-open.org>
cc
Subject
ISSUE 130: New DataObject method: cast()
http://www.osoa.org/jira/browse/SDO-130
Hi Frank,
I had a little trouble entering this into the JIRA: you make a proposal
without stating what problem you would like to solve. Casting to Node
isn't part of the proposal, so XMLFidelity isn't addressed, so what is the
problem we are trying to solve? From your text I have extrapolated the
following DESCRIPTION:
Under SDO 2.1, clients obtain a reference to the static SDO by casting the
DataObject, that is, the static SDO must be the same instance as the
DataObject. This will be a problem when we do JPA/ JAXB integration.
Is this correct?
Now for some questions:
1) don't we need a symetric operation, one that allows you to go from the
static SDO back to the DataObject (casting always worked in both
directions)?
2) what is your justification is for the last assertion, that we need this
for JPA/ JAXB integration?
3) Regarding casting to Node...Assuming we get JAXB integration to work
(by the way, I think JAXB integration is much harder than JPA), doesn't
that give us all the XMLFidelity we need? Which technology should we
focus on integrating?
Best Regards,
Ron
-----Ursprüngliche Nachricht-----
Von: Frank Budinsky [mailto:frankb@ca.ibm.com]
Gesendet: Donnerstag, 12. Juni 2008 00:06
An: sdo@lists.oasis-open.org
Betreff: [sdo] [NEW ISSUE] New DataObject method: cast()
Hi Guys,
I would like to propose adding the following method to the DataObject
interface:
<T> T cast(Class<T> targetClass)
I'm not sure if the name should really be "cast" or "project" or something
else, but I'm thinking "cast" may be best, since the intent is to get some
other interface to work with and view the DataObject.
An implementation of this method will look something like this:
public <T> T cast(Class<T> targetClass)
{
if (targetClass.isInstance(this)) return (T)this;
if (targetClass == Sequence.class && getType().isSequenced()
return getSequence();
// TBD other required or optional casts (e.g., maybe Node.class)
// TBD implementation specific casts
return null; //TBD maybe instead we should throw
ClassCastException
}
The idea behind this method is that it provides a single API for
converting a DataObject to any other possible interface "view".
To get the Sequence view of a DataObject, a user would call:
Sequence sequence = myDO.cast(Sequence.class);
To get the interface of a static SDO, you would call:
Company company = myDO.cast(Company.class);
Using this API instead of simply using Java cast - (Company)myDO - has the
advantage that we've opened up the door for different implementations of
static SDO (e.g., a corresponding POJO) in the future where the static
object and the DataObject are not required to be the same instance. This
will be important when we get to the JAXB/JPA integration discussions.
Once this API is in place, we can think about other (required or optional)
uses for it, such as using it to cast to Node.class (or something else) as
a catch all for the XML Fidelity corner cases that we don't want to handle
in SDO directly.
If we agree to add this new method, I think we should also deprecate
getSequence(), which will have the added benefit of this issue not
actually increasing the number of methods in the DataObject interface.
Thanks,
Frank.
---------------------------------------------------------------------
To unsubscribe from this mail list, you must leave the OASIS TC that
generates this mail. You may a link to this group and all your TCs in
OASIS
at:
https://www.oasis-open.org/apps/org/workgroup/portal/my_workgroups.php
---------------------------------------------------------------------
To unsubscribe from this mail list, you must leave the OASIS TC that
generates this mail. You may a link to this group and all your TCs in
OASIS
at:
https://www.oasis-open.org/apps/org/workgroup/portal/my_workgroups.php
---------------------------------------------------------------------
To unsubscribe from this mail list, you must leave the OASIS TC that
generates this mail. You may a link to this group and all your TCs in
OASIS
at:
https://www.oasis-open.org/apps/org/workgroup/portal/my_workgroups.php
---------------------------------------------------------------------
To unsubscribe from this mail list, you must leave the OASIS TC that
generates this mail. You may a link to this group and all your TCs in OASIS
at:
https://www.oasis-open.org/apps/org/workgroup/portal/my_workgroups.php
---------------------------------------------------------------------
To unsubscribe from this mail list, you must leave the OASIS TC that
generates this mail. You may a link to this group and all your TCs in OASIS
at:
https://www.oasis-open.org/apps/org/workgroup/portal/my_workgroups.php
|