[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[news.eclipse.technology.equinox] Re: Plugins - singletons or not?

Jeff McAffer wrote:

Yes.  I am a little unclear about the need to remove references to classes.
While this may be a good thing in general, clearly plugins are going to
reference classes from other plugins.  Clearing up this one case does not
solve the problem.  So what am I missing here?  Are you proposing that all
cross plugin class references use some sort of service registry mechanism?
As a point of interest, how does that work for subclassing, implementing,
casting etc style relationships?


Plugin subclasses are a special case compared to other classes in the plugin packages because they provide 1)based on the lifecycle, the Plugin subclass provides a logical starting point of initialization for the rest of the plugin and 2) a platform-defined API for accessing a variety of plugin-specific services (for example access to Plugin.getPluginPreferences() provides a very plugin-specific service) without need for visibility of the particular plugin's classes.


In other words, (1) provides reason for subclassing the Plugin class and 2) shows that cross-plugin utilization can happen without specific class visibility.

Once you go beyond that to utilizing discrete classes and interfaces from within the plugin, then you become coupled. The acts of subclassing (extending & implementing) and casting all are compile-time relationships because they require visibility of the classes you are subclassing or casting to. The distinction can thus be generalized to say that if you depend on it at compile time, you will definitely be bound by classloader visibility during run-time. If you can compile without the class, you _may_ be decoupled during run-time, depending on whether you maintain stateful reference to the other plugin's objects.

Thus, a best practice for a component provider is (as Olivier has mentioned repeatedly) to put the public interfaces and abstractions in one 'B' plugin (which would tend to not get unloaded) and put implementations in separate 'C' plugin(s) that can be unloaded.

And a best practice for a component consumer 'A' is to 1) only compile against the 'B' plugin's classes and 2) never retain stateful reference to objects pulled from other plugins.

The difficulty is that in order to hide the classes in 'C' from 'A', they can't be public or exported. So you can't have them directly created by 'B' since to support that they would need to be public.

Thus a third best practice is that the implementing plugin 'C' should only export (a) public factory(s) as it's only public api, keeping all implementation classes internal. 'B' then uses the factory in 'C' to create implementations of 'B's interfaces for use by other plugins such as 'A'. Now, 'A' _is_allowed_ to use 'C's public factory to create the objects, but since the classes are not exported, it would have no way to use them unless it uses 'B's interfaces so it might as well rely on 'B's factories to build the objects.


Since this is not a strongly enforced convention, we may have problems
going forward with unnecessary coupling arising from this.  I guess this
dependency is flagged broadly under the <requires> element.


The <requires> elements tell you that if A requires B and B is shutdown,
replaced, ... A needs to do something.  The straightforward approach is to
shutdown and restart all the dependents (or the whole platform) in these
situations.


Yeah, I think that the straightforward solution is that if A requires B, and B exports any classes, the assumption must be that A requires class visibility and must be shutdown as well. That supports the current model. As an enhancement to the relationship, though, we could extend the plugin.xml so that when A specifies that it <requires> B, it optionally can specify that it listens for events which would allow it to clean up. In that case we would try to unload B without shutting A down as well.


In OSGi (at least some older versions) the old bundle (B) would stay around
until the framework was restarted or all dependent bundles were shutdown and
restarted.  Is this still the state of the art in OSGi?


This is a perfectly legitimate way to handle the problem (multiple instances of the component), so long as this is clear from the start and both the API model and developer conventions have this potential scenario in mind. Otherwise, there obviously is the potential for all kinds of problems such as resource contention.


Mel