You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@jackrabbit.apache.org by Padraic Hannon <pi...@wasabicowboy.com> on 2007/08/17 03:19:02 UTC
dynamic mixins and jcr mapping
I was looking at the default object converter (ObjectConverterImpl) and
noticed that it dynamically adds the ocm:discriminator mixin type to the
jcr node on insert. Additionally I have been thinking about dynamic
languages and looking at Freebase, to make a long story short I am
thinking about dynamic typing of java objects. My thought was that
through a typing (or tagging) mechanism one could create objects with
attribute collections whose values could be validated via jcr if one
could dynamically assign mixins based on a field in that object.
For example, if you have a vehicle feature you may want to tag it as a
transmission and an option. Each tag (or type) would carry a set of
attribute definitions that one would want to see on a web page or in a
data entry system. If you could inspect the object and look at how it is
tagged you could write those tags in as mixins when persisting to jcr.
Then jackrabbit could enforce data types, required fields, etc.
This sort of functionality is a no brainer in dynamically typed systems
such as javascript, ruby, etc. however is not strictly possible in java
(or at least is way out of my league) via interfaces or superclasses,
but could be done via a contract (getTags() getTypes() something like
that) where a method returns mixin names? Does this make anyone
immediately repulsed? I could submit a patch or two to jira if anyone is
interested...
-paddy
Re: dynamic mixins and jcr mapping
Posted by Christophe Lombart <ch...@gmail.com>.
cool this is the fist time that I see a horse which can bark :-)
You are welcome to share your investigation. thanks
Christophe
On 8/29/07, Padraic I. Hannon <pi...@wasabicowboy.com> wrote:
>
> I was playing with cglib over the last few days and found their mixin
> proxy. Using that I was able to do a simple test:
>
> Dog dog = new DogImpl();
> Cat cat = new CatImpl();
>
> Object[] delegates = new Object[2];
> delegates[0] = dog;
> delegates[1] = cat;
> Object mixed = net.sf.cglib.proxy.Mixin.(delegates);
>
> System.out.println(((Dog)mixed).bark());
> System.out.println(((Cat)mixed).meow());
>
> Seems to work fine. You can even add a mixin to a mixin...
>
> Horse horse = new HorseImpl();
> delegates[0] = mixed;
> delegates[1] = horse;
> mixed = net.sf.cglib.proxy.Mixin.(delegates);
>
> System.out.println(((Horse)mixed).neigh());
> System.out.println(((Dog)mixed).bark());
>
> I was thinking that one could create base classes which would be mixin
> implementations and add those during de-serialization from ocm or even
> at runtime to node objects. I'll keep playing and get back with more
> once I have something more concrete.
>
> -paddy
>
Re: dynamic mixins and jcr mapping
Posted by "Padraic I. Hannon" <pi...@wasabicowboy.com>.
For the loading part I ended up doing basically that. Basically I call
addMixin() on the object (which extends a base class I created). The
addMixin method keeps track of all objects added in as mixins to
recreate the mixin each time rather than just nesting them..
public abstract class AbstractJcrModel implements JcrModel {
private Collection mixins = new HashSet();
<SNIP>
public Object addMixin(JcrMixin mixin) {
mixins.add(mixin);
Object[] delegates = mixins.toArray();
delegates = ArrayUtils.add(delegates, 0, this);
return Mixin.create(delegates);
}
}
-paddy
Felix Meschberger wrote:
> Hi Paddy,
>
> Wow ! I was about to apologize to not answered to your mails earlier,
> now I have to admit, that I did not realize, what I missed !
>
> This definitely - from my point of view - like a very interesting path
> to go ! Very interested to see the future.
>
> As a side note on loading: You sketch, that you would load a node in the
> traditional way first and then for each mixin, you would create Mixin
> Object. How about first analyzing the node to get the "primary class"
> and all mixin classes to create the final mixin class upfront and then
> loading all the data into the generated class ? This way, you would not
> generate a cascade of mixin classes.... Just off the top of my head :-)
>
> Regards
> Felix
>
> Am Mittwoch, den 29.08.2007, 12:35 -0700 schrieb Padraic I. Hannon:
>
>> For loading objects, since we now would be relying on interfaces and
>> proxies the reflectionutils.setnestedproperties would no longer work as
>> we would need to address methods instead of bean properties. I'll create
>> a jira ticket if I haven't already to begin tracking code.
>>
>> -paddy
>>
Re: dynamic mixins and jcr mapping
Posted by Felix Meschberger <fm...@gmail.com>.
Hi Paddy,
Wow ! I was about to apologize to not answered to your mails earlier,
now I have to admit, that I did not realize, what I missed !
This definitely - from my point of view - like a very interesting path
to go ! Very interested to see the future.
As a side note on loading: You sketch, that you would load a node in the
traditional way first and then for each mixin, you would create Mixin
Object. How about first analyzing the node to get the "primary class"
and all mixin classes to create the final mixin class upfront and then
loading all the data into the generated class ? This way, you would not
generate a cascade of mixin classes.... Just off the top of my head :-)
Regards
Felix
Am Mittwoch, den 29.08.2007, 12:35 -0700 schrieb Padraic I. Hannon:
> For loading objects, since we now would be relying on interfaces and
> proxies the reflectionutils.setnestedproperties would no longer work as
> we would need to address methods instead of bean properties. I'll create
> a jira ticket if I haven't already to begin tracking code.
>
> -paddy
Re: dynamic mixins and jcr mapping
Posted by "Padraic I. Hannon" <pi...@wasabicowboy.com>.
For loading objects, since we now would be relying on interfaces and
proxies the reflectionutils.setnestedproperties would no longer work as
we would need to address methods instead of bean properties. I'll create
a jira ticket if I haven't already to begin tracking code.
-paddy
Re: dynamic mixins and jcr mapping
Posted by "Padraic I. Hannon" <pi...@wasabicowboy.com>.
I have been looking at the ObjectConverterImpl and I think I have a
strategy for handling mixins that are defined in the mapper but not
assigned to the nodetype in the mapping file.
For inserts one would get the interfaces on the object and loop through
them. For each interface one would look for a class descriptor and add
it to the objectNode one would also get the field, bean, and collection
descriptors for that mixin's class descriptor and add them to the
object's class descriptor.
// Scan Object Interfaces for mixins
Class[] interfaces = object.getClass().getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
ClassDescriptor interfaceDescriptor =
mapper.getClassDescriptorByClass(interfaces[i]);
objectNode.addMixin(interfaceDescriptor.getJcrType().trim());
for (Iterator it =
interfaceDescriptor.getBeanDescriptors().iterator(); it.hasNext(); ) {
classDescriptor.addBeanDescriptor((BeanDescriptor)it.next());
}
for (Iterator it =
interfaceDescriptor.getFieldDescriptors().iterator(); it.hasNext(); ) {
classDescriptor.addFieldDescriptor((FieldDescriptor)it.next());
}
for (Iterator it =
interfaceDescriptor.getCollectionDescriptors().iterator(); it.hasNext(); ) {
classDescriptor.addCollectionDescriptor((CollectionDescriptor)it.next());
}
}
I need to implement it, however, I think directionally this is the right
way to go (??).
Updates would be very similar to inserts.
For loads we have a more interesting story and somewhere I need to spend
more time. I think the steps are:
1) Retrieve object and load fields as described in the mapping file
2) Grab mixins from node
3) For mixins on node which are not in the class descriptor
1) create mixin impl object based on mixin interface name from class
descriptor + Impl (this way one could have more complex methods than
just get/set beans)
2) load fields into mixin impl object
3) use cglib mixin to create a new object containing the base node +
mixin
4) repeat per mixin
Does this sound about right?
-paddy
Re: dynamic mixins and jcr mapping
Posted by "Padraic I. Hannon" <pi...@wasabicowboy.com>.
I was playing with cglib over the last few days and found their mixin
proxy. Using that I was able to do a simple test:
Dog dog = new DogImpl();
Cat cat = new CatImpl();
Object[] delegates = new Object[2];
delegates[0] = dog;
delegates[1] = cat;
Object mixed = net.sf.cglib.proxy.Mixin.(delegates);
System.out.println(((Dog)mixed).bark());
System.out.println(((Cat)mixed).meow());
Seems to work fine. You can even add a mixin to a mixin...
Horse horse = new HorseImpl();
delegates[0] = mixed;
delegates[1] = horse;
mixed = net.sf.cglib.proxy.Mixin.(delegates);
System.out.println(((Horse)mixed).neigh());
System.out.println(((Dog)mixed).bark());
I was thinking that one could create base classes which would be mixin
implementations and add those during de-serialization from ocm or even
at runtime to node objects. I'll keep playing and get back with more
once I have something more concrete.
-paddy
Re: dynamic mixins and jcr mapping
Posted by Christophe Lombart <ch...@gmail.com>.
Thanks for your mail. All kind of ideas are welcome. I agree with you, the
OCM framework has to provide a nice way to map dynamically mixin types.
You are welcome to create a new jira issue. By this way, we can discuss in
more details. Please add use cases. That can help to find a solution :-)
Maybe an solution is not something like this (not yet implemented of
course) - This is just a brain storming. Not sure if it is a good solution.
Transmission transmission = new Transmission();
transmission.setPath("/mytransmission");
transmission.set...();
ocm.insert(transmission);
ocm.save();
... later
Option option = new Option();
option.setPath("/mytransmission");
option.set...();
ocm.update(option);
ocm.save();
If Option is mapped to a mixin:type and if both objects use the same path,
this should work. Later, you can make query/retrieve on both types.
Still thinking about that ...
FYI, I would like to drop the ocm:discriminator. It is used when the same
node type is applied on a complete java class hierarchy in order to find the
appropriate descendant class when a new object has to be instantiated. It is
tedious to support it just to solve this issue.
br,
Christophe
On 8/17/07, Padraic Hannon <pi...@wasabicowboy.com> wrote:
>
> I was looking at the default object converter (ObjectConverterImpl) and
> noticed that it dynamically adds the ocm:discriminator mixin type to the
> jcr node on insert. Additionally I have been thinking about dynamic
> languages and looking at Freebase, to make a long story short I am
> thinking about dynamic typing of java objects. My thought was that
> through a typing (or tagging) mechanism one could create objects with
> attribute collections whose values could be validated via jcr if one
> could dynamically assign mixins based on a field in that object.
>
> For example, if you have a vehicle feature you may want to tag it as a
> transmission and an option. Each tag (or type) would carry a set of
> attribute definitions that one would want to see on a web page or in a
> data entry system. If you could inspect the object and look at how it is
> tagged you could write those tags in as mixins when persisting to jcr.
> Then jackrabbit could enforce data types, required fields, etc.
>
> This sort of functionality is a no brainer in dynamically typed systems
> such as javascript, ruby, etc. however is not strictly possible in java
> (or at least is way out of my league) via interfaces or superclasses,
> but could be done via a contract (getTags() getTypes() something like
> that) where a method returns mixin names? Does this make anyone
> immediately repulsed? I could submit a patch or two to jira if anyone is
> interested...
>
> -paddy
>