Skip to main content

JDNC extensibility

5 replies [Last post]
Anonymous

Hi,

I'm particulary interested in the JDNC markup and would like to let JDNC users
access my own Swing Components while building applications through the markup.

I tried to achieve this and actually managed to do it but I had to hack it
because the current API doesn't seem to me really designed with extensibility
in mind.

Do you plan to provide more extensibility facilities in the future?

For your information here are some examples of problems I encountered. I must
admit I did that just after few minutes playing with JDNC so I may have missed
something in which case I would be happy to know the recommended way to go for
extensions :-)

- To provide your own vocabulary in addition to the one of JDNC you want to
subclass ElementTypes, unfortunately this is a final class, so you have to
duplicate everything. I think this class should not be final.
- To use your own vocabulary you have to modify
Application.getObjectRealizer() method to return your own vocabulary class. I
think the class name of the vocabulary should be customizable throught
resources or command line. Or at least by easing subclassing.
- While coding this I think I encountered some bugs in the sor.jar classes.
Example: I noticed that I was called something in
ComponentElement.getElementHandler(namespace, name) with as name parameter the
full name (NS prefix + localName) instead of the localName as the method code
expect (my markup is using my own namespace with a prefix not JDNC one of
course). (stack of the call comes from ObjectRealizerImpl.findElementType).
- Another point is that if you want your Component to be put in the same
components as for example table you have to sublcass all classes that register
handlers for table (RootPaneElement and so on...). Maybe there could be a
facility that allows to "register" the components from the outside without
having to subclass.
- Some appliers such as preferredSizeApplier explicitely cast the component
(in for example JNTable), if they were only relying on the JComponent
interface (which sounds me perfectly feasible) the appliers could be reused
for other components instead of re-coded.

Thanks,

Christophe.

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Mark Davidson

On 07/12/2004 03:18 AM, Christophe Jolif wrote:
> - To use your own vocabulary you have to modify
> Application.getObjectRealizer() method to return your own vocabulary
> class. I
> think the class name of the vocabulary should be customizable throught
> resources or command line. Or at least by easing subclassing.

We plan to make it public. I just filed this as issue 20.

> - While coding this I think I encountered some bugs in the sor.jar classes.
> Example: I noticed that I was called something in
> ComponentElement.getElementHandler(namespace, name) with as name
> parameter the
> full name (NS prefix + localName) instead of the localName as the method
> code
> expect (my markup is using my own namespace with a prefix not JDNC one of
> course). (stack of the call comes from ObjectRealizerImpl.findElementType).

I think this is a function of an incorrect implementation of
ObjectRealizer.add(). Also, the findElementType implementation is pretty
"hacky". I developed it over the course of a couple of weeks and I
worked backwards from the xml test cases and Junit tests. The
implementation is only as good as the test cases that it can handle.

When we make this LGPL, I'm sure that the quality and efficiency will
improve.

--Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

rameshgupta
Offline
Joined: 2004-06-04

The object realization framework used by JDNC has been designed for extreme extensibility. However, the extensibility features need better documentation, so developers like you can hit the ground running.

Describing the extensibility features in detail will take some time, and it is high priority task on my list. Meanwhile, I'd like to make some quick points:

There are two different ways in which you can use your own components with JDNC.

The first, and the most straightforward way, is to substitute your own subclass for the object realized from a JDNC element type, such as table. If you look in org.jdesktop.jdnc.markup.ElementTypes.java, you will see that a table element is realized as an instance of org.jdesktop.jdnc.JNTable, by default. The JDNC markup language allows you to override that in your markup by specifying an API-compatible class name in the "realizedAs" attribute as follows:

...

According to the language definition, as long as the class you specify is api-compatible with the default realization class, this should work. Unfortunately, the current JDNC tag library implementation does not fully support this extension mechanism yet. The fix is simple -- We just haven't gotten around to it yet :-)

The second way to use your own components with JDNC is to define your own extensions to the language (new tags and/or new attributes). This is what I suspect you are trying to do.

The API for this kind of extensibility has also been carefully thought out. Instead of extending ElementTypes, you would extend net.openmarkup.Vocabulary:

public final class MyElementTypes extends Vocabulary {
// See documentation of net.openmarkup.Vocabulary for restrictions on public
// data members for this class.

public static final ElementType FOO = new ElementType(
MY_NAMESPACE, "foo", "my.markup.elem.FooElement",
"my.own.Foo");

private static Vocabulary instance = null;
public static Vocabulary get() {
if (instance == null) {
instance = new MyElementTypes();
}
return instance;
}
}

You would then implement my.markup.elem.FooElement by extending org.jdesktop.jdnc.markup.elem.ElementProxy. Also implement any element assimilators or attribute appliers that FooElement might need. There are LOTS of examples of these in the org.jdesktop.jdnc.markup.elem and org.jdesktop.jdnc.markup.attr packages!

Finally, you will need to register your custom vocabulary with the object realizer as done by org.jdesktop.jdnc.runner.Application. Unfortunately, I just realized that the static getObjectRealizer() method is not public, but should be. Once that method is made public, you should be able to call the following:

ObjectRealizer objRealizer = Application.getObjectRealizer();

Vocabulary myVocab = MyElementTypes.get(); // see above
objRealizer.add(myVocab);

> - While coding this I think I encountered some bugs
> in the sor.jar classes.
> Example: I noticed that I was called something in
> ComponentElement.getElementHandler(namespace, name)
> with as name parameter the
> full name (NS prefix + localName) instead of the
> localName as the method code
> expect (my markup is using my own namespace with a
> prefix not JDNC one of
> course). (stack of the call comes from
> ObjectRealizerImpl.findElementType).

We will take a look at this one. Thanks for pointing this out.

> - Another point is that if you want your Component to
> be put in the same
> components as for example table you have to sublcass
> all classes that register
> handlers for table (RootPaneElement and so on...).
> Maybe there could be a
> facility that allows to "register" the components
> from the outside without
> having to subclass.

We could make registerElementHandlers() and registerAttributeHandlers() methods public instead of protected in ElementProxy.java.

> - Some appliers such as preferredSizeApplier
> explicitely cast the component
> (in for example JNTable), if they were only relying
> on the JComponent
> interface (which sounds me perfectly feasible) the
> appliers could be reused
> for other components instead of re-coded.
>
> Thanks,
>
> Christophe.

Yes, that is an oversight. It should be fixed as you suggest.

Overall, I congratulate you for having gone as far as you did in such a short time! And thanks for exposing some of our limitations in the process!

Christophe Jolif

Hi,

jdnc-interest@javadesktop.org wrote:

>

> ...
>

>
> According to the language definition, as long as the class you specify
> is api-compatible with the default realization class, this should work.
> Unfortunately, the current JDNC tag library implementation does not
> fully support this extension mechanism yet. The fix is simple --
> We just haven't gotten around to it yet :-)

Anyway as you guessed below this is not my use case. My components are not
"just" subclasses of known components but brand new ones.

> The second way to use your own components with JDNC is to define your
> own extensions to the language (new tags and/or new attributes).
> This is what I suspect you are trying to do.
>
> The API for this kind of extensibility has also been carefully thought out.
> Instead of extending ElementTypes, you would
> extend net.openmarkup.Vocabulary:
>
> public final class MyElementTypes extends Vocabulary {
> // See documentation of net.openmarkup.Vocabulary for restrictions on public
> // data members for this class.
>
> public static final ElementType FOO = new ElementType(
> MY_NAMESPACE, "foo", "my.markup.elem.FooElement",
> "my.own.Foo");
>
> private static Vocabulary instance = null;
> public static Vocabulary get() {
> if (instance == null) {
> instance = new MyElementTypes();
> }
> return instance;
> }
> }
>
> You would then implement my.markup.elem.FooElement by extending
> org.jdesktop.jdnc.markup.elem.ElementProxy. Also implement
> any element assimilators or attribute appliers that FooElement might need.
> There are LOTS of examples of these in the org.jdesktop.jdnc.markup.elem
> and org.jdesktop.jdnc.markup.attr packages!

Yes, I already did that thanks.

> Finally, you will need to register your custom vocabulary with the object realizer as done by
> org.jdesktop.jdnc.runner.Application. Unfortunately, I just
> realized that the static getObjectRealizer() method is not public, but
should be.
> Once that method is made public, you should be able to call the following:
>
> ObjectRealizer objRealizer = Application.getObjectRealizer();
>
> Vocabulary myVocab = MyElementTypes.get(); // see above
> objRealizer.add(myVocab);

Ok I though about doing something like this instead of deriving your
ElementTypes, the problem I see here (in addition to the fact the
getObjectRealizer method is private not public) is that from my experiments
ObjectRealizer.add() does more a set() than a add(). Which means I have my own
Vocabulary registered but the default one is erased! Do you confirm this, or
did I miss something?

Thanks for your faster answers,

Christophe.

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

rameshgupta
Offline
Joined: 2004-06-04

> > Finally, you will need to register your custom
> > vocabulary with the object realizer as done by
> > org.jdesktop.jdnc.runner.Application. [snip]
>
> Ok I though about doing something like this instead
> of deriving your
> ElementTypes, the problem I see here (in addition to
> the fact the
> getObjectRealizer method is private not public) is
> that from my experiments
> ObjectRealizer.add() does more a set() than a add().
> Which means I have my own
> Vocabulary registered but the default one is erased!
> Do you confirm this, or
> did I miss something?

According to the OpenMarkup spec, ObjectRealizer.add() is supposed to add the specified vocabulary to any that are already registered with the object realizer. Element types are registered based on the namespace identifier and the local tag name. Is that not how the Sun implementation of ObjectRealizer is behaving?

Mark Davidson

On 07/13/2004 10:13 AM, j wrote:
>>> Finally, you will need to register your custom vocabulary with
>>> the object realizer as done by
>>> org.jdesktop.jdnc.runner.Application. [snip]
>>
>> Ok I though about doing something like this instead of deriving
>> your ElementTypes, the problem I see here (in addition to the fact
>> the getObjectRealizer method is private not public) is that from my
>> experiments ObjectRealizer.add() does more a set() than a add().
>> Which means I have my own Vocabulary registered but the default one
>> is erased! Do you confirm this, or did I miss something?
>
> According to the OpenMarkup spec, ObjectRealizer.add() is supposed to
> add the specified vocabulary to any that are already registered with
> the object realizer. Element types are registered based on the
> namespace identifier and the local tag name. Is that not how the Sun
> implementation of ObjectRealizer is behaving?

I just checked the implementation of the sor.jar and indeed my add()
will actually replace the vocabulary. This is a bug!

I was discussing the future of the Sun Object Realizer with Ramesh and
we plan to make this a reference implementation as part of the Open
Markup project. https://openmarkup.dev.java.net/.

As part of the reference implementation, I will be contributing my JUnit
tests which use a taglib which is independent of Enode and JDNC which
will act as a "TCK/JCK" for Open Markup implementations.

In the meantime, I could fix the add() bug and update the new version of
sor.jar in the JDNC project repository.

--Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net