On 10/19/11 9:27 PM, Göktürk Gezer wrote:
On Wed, Oct 19, 2011 at 10:13 PM, Pierre-Arnaud Marcelot
<[email protected]>wrote:
Hi Göktürk,
Le 19 oct. 2011 à 19:05, "Göktürk Gezer"<[email protected]> a
écrit :
Hi Pierre,
On Wed, Oct 19, 2011 at 6:36 PM, Pierre-Arnaud Marcelot<[email protected]>wrote:
Hi Dev,
Following our efforts on the OSGI side, I took some time to think about
(and experiment) how we could solve our extensibility issue on the LDAP API,
where we want our users to be able to provide their own custom
implementation of various schema objects like comparators, normalizers, etc.
After a quick discussion with Emmanuel and Guillaume Nodet, it turned out
using OSGI fragments bundles could probably be our best solution.
Hmm, may not be the best, see below.
Here's a definition of what an OSGI fragment bundle is (more information
available at [1]):
"An OSGi fragment is a Java archive file with specific manifest headers
that enable it to attach to a specified host bundle or specified host
bundles in order to function.
Fragments are treated as part of the host bundles. Relevant definitions of
the fragment are merged with the host bundles definitions before the host is
resolved, as long as the information does not conflict.
Fragment dependencies are resolved if possible. If the fragment
dependencies can not be resolved, the fragment does not attach to the host
bundle.
A fragment can not have its own class loader or bundle activator. It can
not override the information present in the host bundles. Fragments extend
bundles with resources, classes, and permitted headers enabling you to
customize your bundles."
Yes, fragments are merged with their host and they left up in the framework
as just resolved, no active state at all. Everything it imports/exports
become host's imports/exports.
The great thing about fragments is that they *share* the same class loader
as their host bundle. Which was pretty much the kind of issue we were having
with classloaders being differents from one bundle to the other.
The other great thing I see with this approach, it that it would also work
great outside of an OSGI container application (which is a strong
requirement for the LDAP API). A fragment bundle is nothing else than a
regular bundle with a specific OSGI directive (Fragment-Host) added to its
MANIFEST.MF file, and a bundle behaves exactly like a plain jar file when
it's not included in an OSGI container. Thus, it would allow us to support
third parties extensions.
It would only allow 3th parties to support their own extensions. Why?.
Because being able to classload the 3th party classes is only half of the
story. We must also know that they've arrived and we must know what has been
arrived. Otherwise we have to hard code their name, ant it is not case in
3th party scenario. Once the fragment is merged with the host, we can class
load them inside host and some other bundle having access to that fragments
specific package? But how do we enforce that package names and class names
across 3th parties?
Actually, that's exactly how it works at the moment. The fully qualified
name of the class is available and read from the schema ldif files. That's
how we get the other half of the story.
If someone wants to extend the schema with a new comparator, for example,
it needs to provide the class and edit the schema to declare the new
comparator.
Hmm. yes i see now. Actually this is a problem of Studio more than DS.
Because it is used to create schemas. So when some 3th party provide custom
elements, its Studio's responsibility to find and list it under
corresponding GUI element. After that, DS can load it using that class name
either with classloading(with fragments) or OSGI.
I have done a small experiment in my Eclipse workspace with two bundles
(one being the host and the other being the fragment ) and I was able to
classload, without any classloader issue, a class defined in the fragment
bundle from another class inside the host bundle.
Did you do it while knowing the class name on the fragment bundle, or not
knowing the class name at all?
Yep, indeed.
I'd like to go a step further and experiment this on the API itself.
Ideally, I'd like to use the 'shared-ldap-model' module
('org.apache.directory.shared.ldap.model' bundle) as a host for all our
schema objects implementations and move these implementations into a
specific fragment bundle containing them all.
Users would have to do the same to include their extensions. A simple
fragment bundle with the 'org.apache.directory.shared.ldap.model' bundle as
host and it works.
Yes it works for us, but for some body writing his own classes, we must
dynamically know they've arrived.
One other thing that should be done, is to let the 'shared-ldap-model'
module do the instanciation of the schema elements. At the moment, two
classes from the 'shared-ldap-schema-data' module are responsible for this,
'org.apache.directory.shared.ldap.schemaloader.SchemaEntityFactory' and
'org.apache.directory.shared.ldap.schemaloader.AttributeClassLoader'. We
would need to move these classes to the 'shared-ldap-model' module, for them
to have access to the right class loader.
All in all, I think that's the only things we need to do to get the
extensibility we wanted inside and outside an OSGI container.
It may bring us to somewhere but not even close to real goals IMO. We can
use them to provide in-house extensions, but when it comes to 3th parties,
it won't be so easy to use that fragments comnig from them inside Shared or
ApacheDS.
Sure, this is some very basic extensibility but it matches perfectly our
needs for the API. On the ApacheDS side, it's another story and we might
probably need something better and more complex.
I was already scared to play with shared anyway, now my fear tripled :) But
i have some good news. I made my use of IPojo and OSGI to not broke existing
shared clients. But i've got one more issue: the OIDs that's got assigned by
constructors, are they static? or is it possible to lets say
BooleanComparator to be instantiated with two different oids. As I see its
not the case and you're maintaining standart OID assigments by hand. What is
the case here?
OIDs are static, and one object can only have one single OID (Object
IDentifier...)
At some point, the guys who invented the OIDs wanted to attribue one OID
for everything on earth...
I have no clear idea about the other part of the mail, but you have to
know that a schema extension (we currently have 3 kind of schema
extensions : Comparator, SyntaxCheckers and Normalizers) can be used in
three different contexts :
- in ApacheDS, so in a fully compliant OSGi environment with an OGSi
container (this is what you are working on)
- in Studio, which is based on Eclipse, so it also uses a container
- in the ldap API, which can perfectly be used without any OSGi
container, and wit h users expecting to be able to classload the
extensions after having put the classes in their classpath.
We must cover those three kind of usage.
--
Regards,
Cordialement,
Emmanuel Lécharny
www.iktek.com