[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
RE: [equinox-dev] Roadmap?
|
That's correct. The UI component framework
is not UI specific. Generally speaking, it provides a loosely-coupled
way to instantiate and destroy objects.
Concretely, here was our driving use-case:
- API Clients are allowed to implement
views and editors (or "parts").
- We wanted to add API such that clients
could host parts.
- Parts have a number of local APIs
available to them, provided by their containing context. We called these
local API "services", but they are more like Eclipse adapters
than OSGi services.
- These service APIs change over time.
- Clients that host parts can offer
an extended set of services to the parts they host.
- All parts need to work in all contexts.
For example:
- If a part updates
itself to use the latest APIs, it should continue to work when hosted in
a context that still implements the old API.
- If a host is updated
to implement the latest APIs, it should continue to be able to host parts
that expect the old version.
- If a part uses
an extended set of features, it should still work in a context that does
not know about the extended features.
- We wanted to be able to act on an
open-ended set of services. For example, it should be possible to write
a wrapper part that overrides a closed set of services and delegates everything
else to another part.
Put simply, we wanted to make all parts
interchangeable, but still leave avenues open for API evolution. These
are issues that apply to any object that gets created from an extension
point, and our implementation was similarly generic. Although the IoC framework
works with any POJO, I will continue using the word "part" since
I find the UI metaphor easiest to visualize.
We wanted our implementation to have
the following properties:
- It must be simpler (require less code
+ XML) to implement a component-based part than a traditional part.
- There must not be a significant memory
or CPU cost to using IoC.
- It must be self-documenting in the
following sense: given a set of plugins, a developer should be able to
generate the list of services that they could use in the implementation
of their part.
- Services can depend on other services.
Since all are created through the framework, there is no real distinction
between the implementation of a "part" and a "service".
Although the framework was originally
intended for views and editors, it is very well suited for any extension
point that calls createExecutableExtension and I have used it for many
non-UI extension points. I do not believe it would work as a replacement
for OSGi's DS, as DS is mainly concerned with dynamic connections between
singletons, whereas the UI IoC stuff is concerned with creating static
connections to objects that can be instantiated anywhere.
Here's how our implementation works:
- Our implementation does NOT require
dependencies to be declared anywhere (no need for a prereqs extension point).
- You only need to say "when someone
asks for service X, create it using factory Y". When it comes time
to create an X, the factory will ask for any services it needs, which get
created dynamically.
- One standard factory, "ReflectionFactory"
creates objects using constructor injection. It would also be possible
to write a setter-injection factory or factories that are specific to a
particular service.
- Although the factories are framework-aware,
the objects they create can truly be POJOs with no framework awareness.
I hope that explains what it can and
can't do. If you want to play with it, you'll find the main IoC container
in org.eclipse.ui.internal.components.framework.Container.
My two cents:
I would not suggest trying to use the
same IoC framework for OSGi services and for createExecutableExtension.
The former are dynamic, so it makes sense to formally declare dependencies
between services in order to defer creation of a service until all of its
dependancies exist. In the case of createExecutableExtension, everything
the object needs will be available immediately if the code is correctly
written. This means that an IoC framework for createExecutableExtension
wouldn't need all the tiresome metadata for describing service dependencies.
Services can just ask for their dependencies the first time they need them.
If this were to be seriously considered
for inclusion in core, I would want to trim a lot of fat first.
Example usage:
class Cat {
String catName;
Cat(String name)
{
catName
= name;
};
}
class Dog {
Cat theCat;
Dog(Cat toChase)
{
theCat
= toChase;
}
public chaseCat()
{
System.out.println("Chasing
" + theCat.getName());
}
}
...
public static void main(String[] args)
{
// Create a context
that knows how to create Dogs. Any time it needs a Cat,
// it will refer
to poor Fluffy.
FactoryMap context
= new FactoryMap()
.add(Dog.class,
new ReflectionFactory(Dog.class))
.addInstance(Cat.class,
new Cat("Fluffy"));
// Create a container
for a particular Dog
Container container
= new Container(context);
try {
//
Create a Dog
Dog
myDog = (Dog)container.getService(Dog.class);
//
Chase Fluffy around
myDog.chaseCat();
} catch (ComponentException
e) {
//
We weren't able to create the Dog
System.out.println(e.toString());
} finally {
//
Clean up the container when no longer needed
container.dispose();
}
}
Pascal Rapicault/Ottawa/IBM
11/22/2005 10:04 PM
|
To
| Equinox development mailing
list <equinox-dev@xxxxxxxxxxx>, Stefan Xenos/Ottawa/IBM@IBMCA
|
cc
| Equinox development mailing
list <equinox-dev@xxxxxxxxxxx>, equinox-dev-bounces@xxxxxxxxxxx
|
Subject
| RE: [equinox-dev] Roadmap?Link |
|
If I remember correctly, the design
of the support for nesting UI component was based of an IoC container and
it had nothing UI specific.
It would be good to see if we could
actually reuse some of the work that had been done there.
Stephan, am I completly smoking? Would
you be able to provide us with some usefull pointers so people can explore?
Thanks,
PaScaL
Jeff McAffer/Ottawa/IBM@IBMCA
Sent by: equinox-dev-bounces@xxxxxxxxxxx
11/22/2005 09:52 PM
Please respond to
Equinox development mailing list |
|
To
| Equinox development mailing
list <equinox-dev@xxxxxxxxxxx>
|
cc
|
|
Subject
| RE: [equinox-dev] Roadmap? |
|
First an answer to your last questions. Yes, anything that makes
writing components easier is very much of interest here. Rather than
creating new programming idioms and mechanisms it would be interesting,
as you have been doing, to investigate all possible avenues. If in
the end there is truly something new here, it may make sense to supply
a library/bundle.
I will offer an alternative that *may* make sense. It is something that
we have been playing with. In the Eclipse extension registry it is
possible to create executable extensions via a factory (see IConfigurationElement.createExecutableExtension()
and IExecutableExtensionFactory). So your IoC framework could publish
an extension point "prereqs" (for lack of a better name). People
who have prereqs (services in your example) to register can then supply
extensions that identify either the actual class to instantiate (if the
simple no-arg constructor is enough) or an IExecutableExtensionFactory
(with args) if more complicated construction is needed.
In the IoC mechanism (com.example.ioc)
<extension-point id="prereqs"/>
In the provider JAR (org.example.provider).
<extension id="prereq1" point="com.example.ioc.prereqs">
<prereq
class="org.example.Factory:coolObject"
...
This extension says run the org.example.Factory and tell it to create the
thing called "coolObject". The factory can be as simple
or as complicated as you like. You can make some generic factories
and share them or make one per thingie you want to create. You can
also pass in an arbitrary number of args statically declared on in the
extension (see the Javadoc for details).
You then have two choices for when the contributed prerequisites are actually
instantiated and supplied to consumers; lazily or aggressively. If
you go for the lazy approach then your POJO could access the prereq on
demand using something like
Object IoC.getPrereq(String prereqName, Object
objectToInject)
where the prereqName is the id of the extension to instantiate (org.example.provider.prereq1
in the above example). (not really a POJO if it is referencing IoC
but you seemed fine with this in your example...) This ends up being
implemented as a call to IConfigurationElement.createExecutableExtension().
The prereq object is only instantiated as needed. When you
stop using it, just drop the pointer. I believe previously you stated that
lifecycle was not important so the disappearance of the provider should
not be an issue.
If you want to create the instances aggressively then the IoC mechanism
should have the sort of registerDependency method you outlined. It
should also implement an IRegistryChangeListener that listens for new extensions
being added to the "prereqs" extension point. When it sees
one that someone has registered an interest in, it calls createExecutableExtension
and uses the supplied setter. If it later sees the extension going
away, it can unset the value. See IExtensionTracker for some utilities
to help manage this.
Some notes:
- You are probably thinking that this is crazy, the extension registry
is buried deep in Eclipse. Wrong! As of today's integration
build it is actually broken out in its own bundle (org.eclipse.equinox.registry)
and the intention it that it run on any OSGi R4 implementation (we've not
tested that part yet).
- So you are still thinking, "but its based on OSGi". Yes
and No. It is pluggable. You can customize the implementation
of the registry to suite different sources of declarations (e.g., something
other than plugin.xml), different namespace management policies and different
mechanisms for implementing createExecutableExtension. We supply
an OSGi registry strategy but you can supply one of your own. The
usecases that are driving this new structure are quite similar to your
hosted and client scenarios.
- The ability to supply dynamic context objects to createExecutableExtension
is currently not implemented. We discussed this late in 3.1 but opted
out. This topic has been raised again and we are certainly open to
adding it.
- I've thought about this exact problem for about as long as it took me
to write this response so I could be completely out to lunch here...
Jeff
"John Wells"
<jwells@xxxxxxx>
Sent by: equinox-dev-bounces@xxxxxxxxxxx
11/22/2005 04:00 PM
Please respond to
Equinox development mailing list |
|
To
| "Equinox development
mailing list" <equinox-dev@xxxxxxxxxxx>
|
cc
|
|
Subject
| RE: [equinox-dev] Roadmap? |
|
Yes, the code using the LogService would have to explicitly check (with
a synchronized block) whether or not the logger exists. The code
would be something like:
LogService localLogger;
synchronized (this) {
localLogger = logService;
}
If (localLogger != null) {
localLogger(“This is fun!!!”);
}
This will work whether or not we are in the OSGi environment.
Also very interesting “trick” to getting the bundle. Thanks. I
wish there was a more “framework independent” way to do this.
My more general question remains though: is this a requirement that
more people than me have faced? Would a Dynamic IoC utility be of
interest to the OSGi community? At this point I’m writing this thing
anyway, I just want to know if people here would be interested in me contributing
the code? Since this is a utility (of course it would be a Bundle
as well) I’m not exactly sure where the proper place would be to put such
a thing, or if people are even interested in such a facility.
John Wells (Aziz)
jwells@xxxxxxx
From: equinox-dev-bounces@xxxxxxxxxxx [mailto:equinox-dev-bounces@xxxxxxxxxxx]
On Behalf Of Jeremy Volkman
Sent: Tuesday, November 22, 2005 2:57 PM
To: Equinox development mailing list
Subject: Re: [equinox-dev] Roadmap?
John,
When writing a component to be environment-agnostic, how do you handle
the case when LogService may not be available
at the time of your POJO's instantiation (only in the OSGi environment,
of course)? Will the programmer have to explicitly check the value
of the logger member before attempting to use it?
If so, doesn't this go against your wishes that the programmer not care
what environment he/she is writing for?
Also, on getting a caller's BundleContext: it is possible, but it get ugly.
I had to do something similar to get per-bundle logging working with
the Apache Commons Logging API. Commons Logging provides the static
LogFactory class to get Log instances, and I wanted Log instances to know
which Bundle had created them (so I could print out the name of the Bundle
logging a message).
One way would be to include a separate copy of my modified LogFactory class
with each bundle, and provide the Bundle's personal LogFactory instance
with a reference to the Bundle at start up, but this seemed like a maintenance
nightmare, and it negated OSGi's nifty code sharing feature.
So i went with the following approach:
1. Subclass SecurityManager and gain access to the getClassContext() method
2. Pick the Class of the caller off the stack
3. Use OSGi's PackageAdmin and its getBundle( java.lang.Class) method to
get the Bundle containing a particular class
Since the BundleContext instance is supposed to be private to its associated
Bundle, OSGi provides no way of getting a BundleContext for a given Bundle
(the DS spec mentions this). With Equinox, this can be done through
reflection, as Equniox's AbstractBundle class defines a method "getContext":
Bundle bundle = ...
Method contextMethod = bundle.getClass().getDeclaredMethod("getContext",
(Class[]) null);
contextMethod.setAccessible(true);
BundleContext context = (BundleContext) contextMethod.invoke(bundle,
(Object[]) null);
Of course there are numerous possible issues with this method (can't create
new SecurityManagers, can't change Method accessibility, etc.), but perhaps
it will be food for thought.
Jeremy Volkman
On 11/22/05, John Wells <
jwells@xxxxxxx> wrote:
Thanks for your response Olivier.
In an earlier response I talked
about the requirement I would like to see satisfied that would make the
IoC pattern work in both a dynamic and a static environment. Basically,
I want to write code that dynamically tells the IoC system that it wants
to depend on some other type and I want this to work both in a "client"
environment where the classes are linked together via the system class-loader
as well in the dynamic environment afforded by OSGi. To me what is
interesting is to be able to write code that runs in both a "hosted"
and "client" environment without modification.
What I do not want is for the
programmers writing the code to know the difference between the two environments.
Furthermore, I think that this could be a common programming pattern
when writing modular code. I want the service writers to have simple
instructions for how to write their services, and then I want the framework
to do the "correct" thing based on whether or not we are running
in the OSGi framework or on a client that has not started the OSGi kernel.
Yes, I want my cake and I want to eat it too ;-)
Let's take something as simple
as a log service. I want to have a pojo that says something like:
private LogServer logger;
…
// inside some method of my
pojo
IoC.createDependency("com.acme.LogService",
"setLogger", this);
…
public synchronized void setLogger(com.acme.LogService
logger) {
this.logger = logger;
}
When in the OSGi world, the
LogService might be satisified by lots of different implementations. However,
in the client world there may be only the one that is satisfied on the
client classpath.. One problem we run up against right away is that
com.acme.LogService is very likely an interface, and hence cannot be instantiated
directly on the client. In order to solve this problem I was thinking
that it would be necessary to define a generic sort of factory interface
like this:
public interface GenericFactory<T>
{
public <T> create(…);
public <T> find(…)
throws NotFoundException;
}
(excuse any typo's, I am typing
as I write, not pasting from an IDE ;-)
Now instead our IoC object might
look like this:
private LogFactory logFactory
= new LogFactory(); // Implements the GenericFactory interface
private LogServer logger;
…
// note this time I must provide
the factory to use for this service
// just in case this is running
in a "client" environment
IoC.createDependency("com.acme.LogService",
"setLogger", this, logFactory);
…
public synchronized void setLogger(com.acme.LogService
logger) {
this.logger = logger;
}
The signature for createDependency
would be something like:
public Object createDependency(String
serviceName, String setterName, GenericFactory staticFactory, …);
where the extra arguments are
used in the find/create methods of the factory.
What my IoC controller could
do then would be that *if* I was running in OSGi (and could find
the bundle context of this caller) then use the ServiceTracker to hook
up the LogService with the implementation. But *if* I was
running in a "client" environment I would use the factory (first
trying to find, then create the service).
Everything above is doable (with
a big question mark on how to get the code's BundleContext) using home-made
code. I was wondering if anyone else has these sorts of requirements
or if there is any "standard" way to accomplish what I am trying
to achieve? And does this clarify what requirements I have?
John Wells (Aziz)
jwells@xxxxxxx
From: equinox-dev-bounces@xxxxxxxxxxx
[mailto:
equinox-dev-bounces@xxxxxxxxxxx]
On Behalf Of Olivier Gruber
Sent: Tuesday, November 22, 2005 12:26 PM
To: Equinox development mailing list
Subject: RE: [equinox-dev] Roadmap?
John,
Declarative services are mostly about lifecycle and injection.
It is the combination of both that is powerful, especially regarding the
linkage with the bundle lifecycle underneath.
That is, a service is created only when its dependencies are available...
and this means that the creations of class loaders are also delayed.
Without lifecycle, injection becomes service tracking with the use of setter/getter
methods,
especially if you are not using a constructor-based injection.
What I am curious about is that inversion of control becomes really interesting
when used with a lifecycle.
The goal is that a service code does not have to deal with the dynamic
nature of its environment.
When it is activated, it has all the references it needs because they have
been injected.
Before loosing a reference, it will be deactivated.
But you are stating that you have no lifecycle, does this mean that you
have injection but your code is also fully
responsible for dynamically appearing/disappearing references? Who controls
that lifecyle? That is, who creates
your POJO and why.
Just trying to understand.
Best regards,
Olivier Gruber, Ph.D.
Persistent & Distributed Object Platforms and Frameworks
IBM TJ Watson Research Center
Yeah I had thought of that too. I guess I wanted it to be sort of
"standardized" rather than having to write a layer. But
that's ok.
So... then I also need to know if/when the "ServiceTracker"
will be
implemented in Equinox. Or perhaps it already is, since I can remember
ServiceTracker from r3?
John Wells (Aziz)
jwells@xxxxxxx
-----Original Message-----
From: equinox-dev-bounces@xxxxxxxxxxx
[mailto:equinox-dev-bounces@xxxxxxxxxxx]
On Behalf Of Jeremy Volkman
Sent: Tuesday, November 22, 2005 11:21 AM
To: Equinox development mailing list
Subject: Re: [equinox-dev] Roadmap?
It seems as though you may be able to realize your DDS needs right now
by using the already-available ServiceTracker. When
registerDependency() is called, create a new ServiceTracker with the
given service information and start it. Override the addingService()
and removedService() methods (or provide a ServiceTrackerCustomizer)
and make these methods call your POJO's setter/unsetter (remember that
this is a dynamic environment, so you'll probably want an unsetter).
The only issue is that you'll need to provide ServiceTracker with a
BundleContext for it to get a ServiceReference.
Jeremy Volkman
On 11/22/05, John Wells <jwells@xxxxxxx>
wrote:
> Yes, I do like the delayed activation part of DS. Here are some
issues
> I have with DS (since you asked - didn't you? ;-)
>
> I would like to be able to have a POJO that uses a service which gets
> injected. While I think that with DS I can declare a class that
the
DS
> would instantiate, what I want is something more dynamic. I
want to
be
> able to have my own class (that I instantiated myself in whatever
way)
> declare that it wants a service (e.g. "com.acme.Foo") injected
into
it.
> This class would *not* be under the lifecycle control of DS, but would
> still be getting the dependent service injected into it appropriately
as
> the class is available in the OSGi framework.
>
> In my mind I have been calling such a facility "Dynamic DS"
or DDS for
> short. It would be a service or a class with static methods
that had
> methods like the following:
>
> /**
> * This method would call the setter on the object when the
appropriate
> * service becomes "available", but objectToInject
is *not* under the
> * specific control of the DS framework
> * Note: There are likely other "registerDependency"
verbs that
specify
> * all the options available in the DS configuration file and
OSGi
> * service filters
> * @param serviceName The name of the service I would like to
depend
on
> * @param setterName The name of the setter - a public void method
that
> * takes the type as the argument
> * @param objectToInject The object (not under the control of
DS) to
> * "inject"
> */
> public static void registerDependency(String serviceName, String
> setterName, Object objectToInject) throws WhateverException;
>
> /**
> * This method removes the dependency, for when the object is
done
> needing
> * the service.
> */
> public static void unregisterDependency(String serviceName, Object
> objectToInject) throws WhateverException;
>
> Obviously, the above is pseudo-code and I wouldn't mind having the
> "registerDependency" return some form of object that can
be used to
> unregister the dependency later. I also wouldn't mind having
the
> registerDependency take some form of other object (e.g. BundleContext)
> that it might need in order to make it work in OSGi. (However,
one of
> the design goals I have is to make any OSGi specific imports not
> visible, so I would almost prefer some sort of wrapper or even
> name-based mechanism).
>
> The basic idea is that independent object can register for injection
> dynamically, and would not have to muck about in the OSGi API in order
> to do service tracking or the like.
>
> Or perhaps there is already a way to do this with the current DS?
I
> looked at the spec and the API, but it is possible I missed something?
> Thanks for helping me understand this a bit more.
>
> And of course, I still need the DS like yesterday ;-).
>
> Anyway, have a nice day.
>
> John Wells (Aziz)
> jwells@xxxxxxx
> -----Original Message-----
> From: equinox-dev-bounces@xxxxxxxxxxx
> [mailto:equinox-dev-bounces@xxxxxxxxxxx]
On Behalf Of BJ Hargrave
> Sent: Tuesday, November 22, 2005 10:34 AM
> To: Equinox development mailing list
> Subject: Re: [equinox-dev] Roadmap?
>
> IBM is in the process of preparing a contribution of a Declarative
> Services implementation (among other selected services). Stay tuned...
>
> I would have to say Declarative Service is the best to use. But in
the
> interest of full disclosure, I was the designer of Declarative
Services
> :-) I am also not very familiar with GBeans. But DS does fully
integrate
>
> with the OSGi service model and has certain desirable performance
> characteristics such as delayed activation.
>
> BJ Hargrave
> Senior Technical Staff Member, IBM
> OSGi Fellow and CTO of the OSGi Alliance
> hargrave@xxxxxxxxxx
> Office: +1 407 849 9117 Mobile: +1 386 848 3788
>
>
>
> "John Wells" <jwells@xxxxxxx>
> Sent by: equinox-dev-bounces@xxxxxxxxxxx
> 2005-11-22 10:00 AM
> Please respond to
> Equinox development mailing list
>
>
> To
> <equinox-dev@xxxxxxxxxxx>
> cc
>
> Subject
> [equinox-dev] Roadmap?
>
>
>
>
>
>
> Is there a roadmap for Equinox, especially where it concerns the
> compendium services of r4? In particular, I am interested in
using
the
> Declarative Services Specification?
>
> I have been looking around to see if I could find information about
it
> (dss), but haven?t found anything other than a handful of mail in
the
> archive. In particular, I need to have a good idea when (if)
dss is
> going
> to be implemented. I?ve even considered just implementing that
part
of
> the specification myself in order to get it quicker.
>
> Also:
>
> Both DSS and GBeans are IoC frameworks. Does anyone have any
opinions
> on
> which are easier to use? Better? Any pros/cons?
>
> John Wells (Aziz)
> jwells@xxxxxxx
> _______________________________________________
> equinox-dev mailing list
> equinox-dev@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/equinox-dev
>
>
> _______________________________________________
> equinox-dev mailing list
> equinox-dev@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/equinox-dev
>
> _______________________________________________
> equinox-dev mailing list
> equinox-dev@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/equinox-dev
>
_______________________________________________
equinox-dev mailing list
equinox-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/equinox-dev
_______________________________________________
equinox-dev mailing list
equinox-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/equinox-dev
_______________________________________________
equinox-dev mailing list
equinox-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/equinox-dev
_______________________________________________
equinox-dev mailing list
equinox-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/equinox-dev
_______________________________________________
equinox-dev mailing list
equinox-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/equinox-dev