[xwiki-devs] [Proposal] Choosing the default component implementation
Hi devs, Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible. Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint. I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example: com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation. If there's no mapping for a component, we'll continue to use the "default" hint. I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to. In the future we could change existing components to give proper hints instead of "default", where such a change is applicable. Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it. WDYT? -- Sergiu Dumitriu http://purl.org/net/sergiu/
Hi Sergiu, I think that components and xwiki defaults are 2 distinct issues, and here you're talking about defaults for xwiki (meta) services, not the defaults for what a service means from a (lower level) component pov. At component level, from my pov, default means "I don't care, I just need one". At xwiki services level (storage, authentication, datamigration, etc), default means: "whichever is considered "standard" in the running instance of xwiki". I understand the need (which is why I love declarative wiring of components, a la osgi/apache felix), yet I'm not 100% sure that we need another mechanism to make it happen. We have already changed the component overriding mechanism to allow potentially infinite overriding, changing the 'default' implementation in the whole instance can be achieved with this. Also, we could still keep these configs in the xwiki.cfg/xwiki.properties file (yet another configuration file components-defaults.txt would be a pain from my pov) and change the behaviour of the component manager (yey) to take that into account on lookup. In the end, it _is_ about configuration (whether your xwiki should use hibernate or other store). Actually there's a third thing: the fact that default is not reflecting the technology and for that there is a simple solution: you can have multiple hints for a component. Thus, a hibernate thingy would have hibernate and default hints. However, you need to check that the Component manager is giving you the same instance when you ask for one or the other of the hints (I think there was an issue like that with components implementing multiple roles). <see below for more> On 04/05/2012 05:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
Why? if they requested the default, as per my starting remark, it means "I don't care, I just need one". So why should it matter that the implementation changed? Actually, if all the hint changes we make are about replacing default implementations with hinted implementations and using the new hint as the default, there shouldn't be any problem for the user. If we change the default implementation itself, we'd need to announce that regardless of the way we use to configure that (using default hint or proxying the default with a declarative, overridable wiring) .
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
I'm not sure we need that. We can consider it's a namespaced name and that "default" means "default in xwiki".
WDYT?
In the end I agree, I think it's a good idea to: 1/ remove the obligation of having one component that has the hint default 2/ allowing the default to be wired at "configuration phase" rather than at "development phase", in a declarative file that an admin can more easily operate with. but it shouldn't be in "yet another configuration file", it should be in one of the standard configuration files (actually the one and only xwiki.properties since xwiki.cfg is obsolete), where we have traditionally stored the default implementations for various "xwiki services". Thanks, Anca P.S. sorry for the potential ideas mess above, I was writing as I was thinking.
Hi Sergiu, On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
WDYT?
This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one). To decide which implementation is used you use a priority order, as described on: http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr... I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it. Thanks -Vincent
On 04/05/2012 06:42 PM, Vincent Massol wrote:
Hi Sergiu,
On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
WDYT? This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one).
To decide which implementation is used you use a priority order, as described on: http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr...
I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it.
One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki. Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default.
Thanks -Vincent
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
On 04/05/2012 12:51 PM, Anca Luca wrote:
On 04/05/2012 06:42 PM, Vincent Massol wrote:
Hi Sergiu,
On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
WDYT? This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one).
To decide which implementation is used you use a priority order, as described on: http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr...
I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it.
"...choosing the default between alternative implementations that should all **still be usable by themselves** is not possible" The overrides mechanism allows to change which component will be returned for the "default" hint, but all the others will be invisible.
One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki.
Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default.
Exactly. For most of the "services" the XWiki platform currently has (storage, cache), we don't have a "default" implementation, but we rely on a kind of factory to lookup the configured default. That is an actual factory class in the case of the cache service, but just more code in the old XWiki.java class for the storage initialization. A standard way of selecting the default means that we'll need less factories, and less code is always a good thing. Now, suppose one of the older components that had only one implementation, "default", gets alternative implementations, and we want to be able to allow more than one to be active in a wiki, and let the administrator decide which one should be considered the default. How can we approach this? The only way is indeed to have multiple hints, but last time I checked this resulted in more than one instance, even for @Singleton implementations. Another approach is to deprecate the direct dependency declaration and instead introduce a factory that is responsible for selecting the default, but this breaks backwards compatibility. The "I don't care, just give me the default" strategy works as long as the component implementation is self-contained and doesn't involve data communication. Let's take an example, PDF export. Currently the PDF export is only possible via FOP. If we were to convert the current interface + implementation class into a proper component, we'd name it "default", since it's the only one and who needs a factory for only one implementation. People use it and they're happy because it just works. But we might soon add support for export via an office server. Suppose we want either FOP or Office to be usable as the default PDF export implementation. And suppose we'll want to keep both types of export active, so that we can use either one as the implementation for the default export of documents, the FOP implementation for exporting some kinds of documents like scientific articles, and the office connector for generating PDFs for presentations. Using the overrides mechanism we can only have one active at the same time, unless we introduce yet another factory which we can bypass using manual component lookup. If at some point we decide that the office implementation works better, we might consider changing the default implementation for the pdf component. This means that we'll change the hint of the FOP implementation from "default" to "fop", change the hint of the Office implementation from "office" to "default", and our new version of XE works great if people read the installation guide and properly configure the office connector. But what about those that want to upgrade, but are happy with the older FOP implementation and don't want to add support for the office connector? They'll have to use patched versions of the two component implementations where their hints are reverted back to the old values. Easy? No. And even though "default" means "I don't care what the implementation does", here it does matter a lot which implementation you're using. They have different requirements, and it's important to know if the implementation will require an office instance or not. Saying that this won't happen since we're all really careful when designing our components is wishful thinking. We've refactored other more critical pieces of code than providing alternative implementations for a component, so we will find ourselves in situations where we'll have to switch from only one "default" implementation to several. Designing our component manager to make it easy to transition is the right thing to do. Still, my major problem is not about overrides, but about the semantics of "default" (or lack of it). This says nothing about the actual mechanisms behind the implementation, it just reflects the state of that particular component implementation: it's the default at the moment. Not caring what the implementation actually does works only when there is indeed just one possible implementation that is straight-forward. But in most cases, we do rely on another library that does the work for us, and libraries die, better alternatives come along, and changing that internal aspect of the implementation will sometimes be backwards incompatible, or have a different behavior. Sure, it does the same job, but it does it so differently that some will prefer to use the other approach. We have to let users decide which is their "default", and having multiple implementations with the "default" hint but different priorities is not very intuitive. Why not make everything default and remove hints completely if we don't really put any meaning into the hint? And "default" adds another assumption: XWiki Enterprise is the ultimate target. Our defaults are the only ones that matter. As an example, all the *Configuration components have just one "default" implementation, which relies on xwiki.properties, XWiki.XWikiPreferences etc. Doesn't that tie the platform to the XWiki Enterprise wiki? It's not a direct dependency visible at compilation time, it's worse, and invisible assumption about the final runtime. It's certainly not the default for other types of users that want to embed xwiki-commons or xwiki-platform components in a different type of end product. To me this isn't the default configuration, this is the default configuration used by XWiki Enterprise, thus my proposal of using something else as the generic component hint instead of "default". -- Sergiu Dumitriu http://purl.org/net/sergiu/
On Thu, Apr 5, 2012 at 8:44 PM, Sergiu Dumitriu <[email protected]> wrote:
On 04/05/2012 12:51 PM, Anca Luca wrote:
On 04/05/2012 06:42 PM, Vincent Massol wrote:
Hi Sergiu,
On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
WDYT?
This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one).
To decide which implementation is used you use a priority order, as described on:
http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr...
I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it.
"...choosing the default between alternative implementations that should all **still be usable by themselves** is not possible"
The overrides mechanism allows to change which component will be returned for the "default" hint, but all the others will be invisible.
One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki.
Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default.
Exactly. For most of the "services" the XWiki platform currently has (storage, cache), we don't have a "default" implementation, but we rely on a kind of factory to lookup the configured default. That is an actual factory class in the case of the cache service, but just more code in the old XWiki.java class for the storage initialization. A standard way of selecting the default means that we'll need less factories, and less code is always a good thing.
Now, suppose one of the older components that had only one implementation, "default", gets alternative implementations, and we want to be able to allow more than one to be active in a wiki, and let the administrator decide which one should be considered the default. How can we approach this? The only way is indeed to have multiple hints, but last time I checked this resulted in more than one instance, even for @Singleton implementations.
Yep different role or hint produce different instances but AFAIK it's not really an explicit choose but more lazyness since it's a bit more complex (just a bit and is not technical reason to prevent to support it if we want to). The thing is that we often restraint what our CM can do because there is still the idea that it's a (starting to be old) "temporary" implementation and that we would move to another implementation like Guice, OSGI, etc. at one point.
Another approach is to deprecate the direct dependency declaration and instead introduce a factory that is responsible for selecting the default, but this breaks backwards compatibility.
The "I don't care, just give me the default" strategy works as long as the component implementation is self-contained and doesn't involve data communication. Let's take an example, PDF export.
Currently the PDF export is only possible via FOP. If we were to convert the current interface + implementation class into a proper component, we'd name it "default", since it's the only one and who needs a factory for only one implementation. People use it and they're happy because it just works. But we might soon add support for export via an office server. Suppose we want either FOP or Office to be usable as the default PDF export implementation. And suppose we'll want to keep both types of export active, so that we can use either one as the implementation for the default export of documents, the FOP implementation for exporting some kinds of documents like scientific articles, and the office connector for generating PDFs for presentations. Using the overrides mechanism we can only have one active at the same time, unless we introduce yet another factory which we can bypass using manual component lookup.
If at some point we decide that the office implementation works better, we might consider changing the default implementation for the pdf component. This means that we'll change the hint of the FOP implementation from "default" to "fop", change the hint of the Office implementation from "office" to "default", and our new version of XE works great if people read the installation guide and properly configure the office connector. But what about those that want to upgrade, but are happy with the older FOP implementation and don't want to add support for the office connector? They'll have to use patched versions of the two component implementations where their hints are reverted back to the old values. Easy? No. And even though "default" means "I don't care what the implementation does", here it does matter a lot which implementation you're using. They have different requirements, and it's important to know if the implementation will require an office instance or not.
Saying that this won't happen since we're all really careful when designing our components is wishful thinking. We've refactored other more critical pieces of code than providing alternative implementations for a component, so we will find ourselves in situations where we'll have to switch from only one "default" implementation to several. Designing our component manager to make it easy to transition is the right thing to do.
Still, my major problem is not about overrides, but about the semantics of "default" (or lack of it). This says nothing about the actual mechanisms behind the implementation, it just reflects the state of that particular component implementation: it's the default at the moment. Not caring what the implementation actually does works only when there is indeed just one possible implementation that is straight-forward. But in most cases, we do rely on another library that does the work for us, and libraries die, better alternatives come along, and changing that internal aspect of the implementation will sometimes be backwards incompatible, or have a different behavior. Sure, it does the same job, but it does it so differently that some will prefer to use the other approach. We have to let users decide which is their "default", and having multiple implementations with the "default" hint but different priorities is not very intuitive. Why not make everything default and remove hints completely if we don't really put any meaning into the hint?
And "default" adds another assumption: XWiki Enterprise is the ultimate target. Our defaults are the only ones that matter. As an example, all the *Configuration components have just one "default" implementation, which relies on xwiki.properties, XWiki.XWikiPreferences etc. Doesn't that tie the platform to the XWiki Enterprise wiki? It's not a direct dependency visible at compilation time, it's worse, and invisible assumption about the final runtime. It's certainly not the default for other types of users that want to embed xwiki-commons or xwiki-platform components in a different type of end product. To me this isn't the default configuration, this is the default configuration used by XWiki Enterprise, thus my proposal of using something else as the generic component hint instead of "default".
-- Sergiu Dumitriu http://purl.org/net/sergiu/ _______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
-- Thomas Mortagne
On Fri, Apr 6, 2012 at 9:16 AM, Thomas Mortagne <[email protected]> wrote:
On Thu, Apr 5, 2012 at 8:44 PM, Sergiu Dumitriu <[email protected]> wrote:
On 04/05/2012 12:51 PM, Anca Luca wrote:
On 04/05/2012 06:42 PM, Vincent Massol wrote:
Hi Sergiu,
On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
WDYT?
This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one).
To decide which implementation is used you use a priority order, as described on:
http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr...
I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it.
"...choosing the default between alternative implementations that should all **still be usable by themselves** is not possible"
The overrides mechanism allows to change which component will be returned for the "default" hint, but all the others will be invisible.
One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki.
Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default.
Exactly. For most of the "services" the XWiki platform currently has (storage, cache), we don't have a "default" implementation, but we rely on a kind of factory to lookup the configured default. That is an actual factory class in the case of the cache service, but just more code in the old XWiki.java class for the storage initialization. A standard way of selecting the default means that we'll need less factories, and less code is always a good thing.
Now, suppose one of the older components that had only one implementation, "default", gets alternative implementations, and we want to be able to allow more than one to be active in a wiki, and let the administrator decide which one should be considered the default. How can we approach this? The only way is indeed to have multiple hints, but last time I checked this resulted in more than one instance, even for @Singleton implementations.
Yep different role or hint produce different instances but AFAIK it's not really an explicit choose but more lazyness since it's a bit more complex (just a bit and is not technical reason to prevent to support it if we want to). The thing is that we often restraint what our CM
s/restraint/restrain/
can do because there is still the idea that it's a (starting to be old) "temporary" implementation and that we would move to another implementation like Guice, OSGI, etc. at one point.
Another approach is to deprecate the direct dependency declaration and instead introduce a factory that is responsible for selecting the default, but this breaks backwards compatibility.
The "I don't care, just give me the default" strategy works as long as the component implementation is self-contained and doesn't involve data communication. Let's take an example, PDF export.
Currently the PDF export is only possible via FOP. If we were to convert the current interface + implementation class into a proper component, we'd name it "default", since it's the only one and who needs a factory for only one implementation. People use it and they're happy because it just works. But we might soon add support for export via an office server. Suppose we want either FOP or Office to be usable as the default PDF export implementation. And suppose we'll want to keep both types of export active, so that we can use either one as the implementation for the default export of documents, the FOP implementation for exporting some kinds of documents like scientific articles, and the office connector for generating PDFs for presentations. Using the overrides mechanism we can only have one active at the same time, unless we introduce yet another factory which we can bypass using manual component lookup.
If at some point we decide that the office implementation works better, we might consider changing the default implementation for the pdf component. This means that we'll change the hint of the FOP implementation from "default" to "fop", change the hint of the Office implementation from "office" to "default", and our new version of XE works great if people read the installation guide and properly configure the office connector. But what about those that want to upgrade, but are happy with the older FOP implementation and don't want to add support for the office connector? They'll have to use patched versions of the two component implementations where their hints are reverted back to the old values. Easy? No. And even though "default" means "I don't care what the implementation does", here it does matter a lot which implementation you're using. They have different requirements, and it's important to know if the implementation will require an office instance or not.
Saying that this won't happen since we're all really careful when designing our components is wishful thinking. We've refactored other more critical pieces of code than providing alternative implementations for a component, so we will find ourselves in situations where we'll have to switch from only one "default" implementation to several. Designing our component manager to make it easy to transition is the right thing to do.
Still, my major problem is not about overrides, but about the semantics of "default" (or lack of it). This says nothing about the actual mechanisms behind the implementation, it just reflects the state of that particular component implementation: it's the default at the moment. Not caring what the implementation actually does works only when there is indeed just one possible implementation that is straight-forward. But in most cases, we do rely on another library that does the work for us, and libraries die, better alternatives come along, and changing that internal aspect of the implementation will sometimes be backwards incompatible, or have a different behavior. Sure, it does the same job, but it does it so differently that some will prefer to use the other approach. We have to let users decide which is their "default", and having multiple implementations with the "default" hint but different priorities is not very intuitive. Why not make everything default and remove hints completely if we don't really put any meaning into the hint?
And "default" adds another assumption: XWiki Enterprise is the ultimate target. Our defaults are the only ones that matter. As an example, all the *Configuration components have just one "default" implementation, which relies on xwiki.properties, XWiki.XWikiPreferences etc. Doesn't that tie the platform to the XWiki Enterprise wiki? It's not a direct dependency visible at compilation time, it's worse, and invisible assumption about the final runtime. It's certainly not the default for other types of users that want to embed xwiki-commons or xwiki-platform components in a different type of end product. To me this isn't the default configuration, this is the default configuration used by XWiki Enterprise, thus my proposal of using something else as the generic component hint instead of "default".
-- Sergiu Dumitriu http://purl.org/net/sergiu/ _______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
-- Thomas Mortagne
-- Thomas Mortagne
Hi Sergiu, Note that below I'm going to play the devil's advocate since I think it's important we really think hard before changing anything and verify if our current implementation is not enough. See below. On Apr 5, 2012, at 8:44 PM, Sergiu Dumitriu wrote:
On 04/05/2012 12:51 PM, Anca Luca wrote:
On 04/05/2012 06:42 PM, Vincent Massol wrote:
Hi Sergiu,
On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
WDYT? This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one).
To decide which implementation is used you use a priority order, as described on: http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr...
I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it.
"...choosing the default between alternative implementations that should all **still be usable by themselves** is not possible"
The overrides mechanism allows to change which component will be returned for the "default" hint, but all the others will be invisible.
One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki.
Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default.
Exactly. For most of the "services" the XWiki platform currently has (storage, cache), we don't have a "default" implementation, but we rely on a kind of factory to lookup the configured default. That is an actual factory class in the case of the cache service, but just more code in the old XWiki.java class for the storage initialization.
Yep that's how it works.
A standard way of selecting the default means that we'll need less factories, and less code is always a good thing.
Yes but it has more limitation to what we have since with a proper Factory you can imagine all kind of logic to decide which implementation to use (hour of the day, whether the user is a premium user or not, etc). BTW we do support Providers and the goal of the Provider is to be a factory for a given Role. So from now on, there should be no need to implement a Factory proper. Implementing a Provider is the new best practice for this.
Now, suppose one of the older components that had only one implementation, "default", gets alternative implementations, and we want to be able to allow more than one to be active in a wiki, and let the administrator decide which one should be considered the default. How can we approach this? The only way is indeed to have multiple hints, but last time I checked this resulted in more than one instance, even for @Singleton implementations.
Correct, ATM we support only one hint per implementation.
Another approach is to deprecate the direct dependency declaration and instead introduce a factory that is responsible for selecting the default, but this breaks backwards compatibility.
Not completely true. Imagine you have (Role, "default") as your current component and you wish to be able to choose various implementation from now on. What you could do is this: * Write a new component, a Factory, that overrides the current component, i.e. by using the same (Role, "default"). This factory will then delegate to whatever other implementation it wishes. From the user of (Role, "default")'s POV he won't see a single change.
The "I don't care, just give me the default" strategy works as long as the component implementation is self-contained and doesn't involve data communication. Let's take an example, PDF export.
Currently the PDF export is only possible via FOP. If we were to convert the current interface + implementation class into a proper component, we'd name it "default", since it's the only one and who needs a factory for only one implementation.
Yes but we could also be thorough and instead implement a Provider<PDFExporter> instead.
People use it and they're happy because it just works. But we might soon add support for export via an office server. Suppose we want either FOP or Office to be usable as the default PDF export implementation. And suppose we'll want to keep both types of export active, so that we can use either one as the implementation for the default export of documents, the FOP implementation for exporting some kinds of documents like scientific articles, and the office connector for generating PDFs for presentations. Using the overrides mechanism we can only have one active at the same time, unless we introduce yet another factory which we can bypass using manual component lookup.
Based on your use case you'll need a UI to ask the user what he wants to export, i.e. either a "scientific article" or a "presentation" and from his choice you'll pick the right implementation. You could also try to guess that dynamically by looking at what is being exported but that'll require a Factory to hold that logic. I know what you mean though: for some reason you don't want that to be dynamic and you wish it to be static. There's a problem with dynamicity though. Imagine an extension that wants to replace an implementation. With your proposal the best practice would be to introduce a new Hint since the "default" is chosen statically at configuration time. So that wouldn't work. After you install extensions you'd need to stop the wiki, change the binding to the new implementation from the extension and restart it. Of course you'd need to read the documentation of the extension to know you have to use it in replacement. Basically it would mean that extensions cannot override behaviors. They would just be able to add new components (like new Macros) but not modify behaviors at runtime.
If at some point we decide that the office implementation works better, we might consider changing the default implementation for the pdf component. This means that we'll change the hint of the FOP implementation from "default" to "fop", change the hint of the Office implementation from "office" to "default", and our new version of XE works great if people read the installation guide and properly configure the office connector.
In practice we would have 2 choices with our current component impl.: Choice 1: * Add 2 new implementations with hint1 and hint2 (hint1 being what was "default" before) * Keep the implementation with "default" hint but deprecate it and move it to legacy. Refactor it so that it delegates yo hint1 * Add a Provider to decide which impl to use based on whatever conditions we want Choice 2: * Move "default" impl to "hint1" * Add "hint2" * Change "default" implementation to be a Composite that delegates to hint1 or hint2
But what about those that want to upgrade, but are happy with the older FOP implementation and don't want to add support for the office connector?
Yes, in this case this is transparent for them (and it's a good thing in most caes!). This means they get autoupgrade to something better.
They'll have to use patched versions of the two component implementations where their hints are reverted back to the old values. Easy? No. And even though "default" means "I don't care what the implementation does"
It doesn't really mean this. We use "default" only when there's a single implementation. When there are more than 1 each one has a hint that is a qualifier to the implementation since there's no reason one is more default than the other.
, here it does matter a lot which implementation you're using. They have different requirements, and it's important to know if the implementation will require an office instance or not.
Saying that this won't happen since we're all really careful when designing our components is wishful thinking. We've refactored other more critical pieces of code than providing alternative implementations for a component, so we will find ourselves in situations where we'll have to switch from only one "default" implementation to several.
I agree that we've refactored. And it has worked so far right? ;)
Designing our component manager to make it easy to transition is the right thing to do.
Still, my major problem is not about overrides, but about the semantics of "default" (or lack of it). This says nothing about the actual mechanisms behind the implementation, it just reflects the state of that particular component implementation: it's the default at the moment. Not caring what the implementation actually does works only when there is indeed just one possible implementation that is straight-forward. But in most cases, we do rely on another library that does the work for us, and libraries die, better alternatives come along, and changing that internal aspect of the implementation will sometimes be backwards incompatible, or have a different behavior. Sure, it does the same job, but it does it so differently that some will prefer to use the other approach. We have to let users decide which is their "default", and having multiple implementations with the "default" hint but different priorities is not very intuitive. Why not make everything default and remove hints completely if we don't really put any meaning into the hint?
And "default" adds another assumption: XWiki Enterprise is the ultimate target. Our defaults are the only ones that matter. As an example, all the *Configuration components have just one "default" implementation, which relies on xwiki.properties, XWiki.XWikiPreferences etc. Doesn't that tie the platform to the XWiki Enterprise wiki?
This not true in xwiki commons and rendering because I've made sure that we could use them outside of the XWiki Platform. They have default implementation that don't use XWiki Configuration module.
It's not a direct dependency visible at compilation time, it's worse, and invisible assumption about the final runtime. It's certainly not the default for other types of users that want to embed xwiki-commons or xwiki-platform components in a different type of end product. To me this isn't the default configuration, this is the default configuration used by XWiki Enterprise, thus my proposal of using something else as the generic component hint instead of "default".
Ok thanks for the explanations. I understand better now what you mean. Actually what you suggest could already be implemented using a best practice of always using Providers when you want a Component injected. In this manner by default you'll get the Generic Provider but anyone could implement a specific Provider implementation for it that would choose between various implementation based on whatever (a value in a META-INF/role-bindings.txt file, data from DB, etc). <side note>Only issue with having Providers everywhere is that you get late verification of your system coherence since dependencies will be resolved only when they're used. OTOH this is a necessity in a fully-dynamic system ;)</side note> Also, the notion of default doesn't always have a meaning. There are lots of cases when there are NO default. For example Macros or Transformations or… Let's continue the discussion it's interesting :) I'd like to review a bit the other Component system out there again to see what they do for this. It's important that they have support for this since we want to be able to switch to them one day. The 3 that I would review are: * Guice * CDI * OSGi Thanks -Vincent
I On 04/06/2012 09:35 AM, Vincent Massol wrote:
Hi Sergiu,
Note that below I'm going to play the devil's advocate since I think it's important we really think hard before changing anything and verify if our current implementation is not enough.
See below.
On Apr 5, 2012, at 8:44 PM, Sergiu Dumitriu wrote:
On 04/05/2012 12:51 PM, Anca Luca wrote:
On 04/05/2012 06:42 PM, Vincent Massol wrote:
Hi Sergiu,
On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
WDYT? This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one).
To decide which implementation is used you use a priority order, as described on: http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr...
I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it. "...choosing the default between alternative implementations that should all **still be usable by themselves** is not possible"
The overrides mechanism allows to change which component will be returned for the "default" hint, but all the others will be invisible.
One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki.
Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default. Exactly. For most of the "services" the XWiki platform currently has (storage, cache), we don't have a "default" implementation, but we rely on a kind of factory to lookup the configured default. That is an actual factory class in the case of the cache service, but just more code in the old XWiki.java class for the storage initialization. Yep that's how it works.
A standard way of selecting the default means that we'll need less factories, and less code is always a good thing. Yes but it has more limitation to what we have since with a proper Factory you can imagine all kind of logic to decide which implementation to use (hour of the day, whether the user is a premium user or not, etc).
BTW we do support Providers and the goal of the Provider is to be a factory for a given Role. So from now on, there should be no need to implement a Factory proper. Implementing a Provider is the new best practice for this.
Now, suppose one of the older components that had only one implementation, "default", gets alternative implementations, and we want to be able to allow more than one to be active in a wiki, and let the administrator decide which one should be considered the default. How can we approach this? The only way is indeed to have multiple hints, but last time I checked this resulted in more than one instance, even for @Singleton implementations. Correct, ATM we support only one hint per implementation.
? I think Marius needed that for some wysiwyg stuff and we actually support multiple hints per implementation. It's just gonna give you a new instance for each hint, which in my view is a bug, not a missing feature.
Another approach is to deprecate the direct dependency declaration and instead introduce a factory that is responsible for selecting the default, but this breaks backwards compatibility. Not completely true. Imagine you have (Role, "default") as your current component and you wish to be able to choose various implementation from now on. What you could do is this:
* Write a new component, a Factory, that overrides the current component, i.e. by using the same (Role, "default"). This factory will then delegate to whatever other implementation it wishes.
That's only possible if the public API of the CM allows you to grab overriden components (non-default defaults :) )
From the user of (Role, "default")'s POV he won't see a single change.
The "I don't care, just give me the default" strategy works as long as the component implementation is self-contained and doesn't involve data communication. Let's take an example, PDF export.
Currently the PDF export is only possible via FOP. If we were to convert the current interface + implementation class into a proper component, we'd name it "default", since it's the only one and who needs a factory for only one implementation. Yes but we could also be thorough and instead implement a Provider<PDFExporter> instead.
People use it and they're happy because it just works. But we might soon add support for export via an office server. Suppose we want either FOP or Office to be usable as the default PDF export implementation. And suppose we'll want to keep both types of export active, so that we can use either one as the implementation for the default export of documents, the FOP implementation for exporting some kinds of documents like scientific articles, and the office connector for generating PDFs for presentations. Using the overrides mechanism we can only have one active at the same time, unless we introduce yet another factory which we can bypass using manual component lookup. Based on your use case you'll need a UI to ask the user what he wants to export, i.e. either a "scientific article" or a "presentation" and from his choice you'll pick the right implementation. You could also try to guess that dynamically by looking at what is being exported but that'll require a Factory to hold that logic.
I know what you mean though: for some reason you don't want that to be dynamic and you wish it to be static.
There's a problem with dynamicity though. Imagine an extension that wants to replace an implementation. With your proposal the best practice would be to introduce a new Hint since the "default" is chosen statically at configuration time. So that wouldn't work. After you install extensions you'd need to stop the wiki, change the binding to the new implementation from the extension and restart it. Of course you'd need to read the documentation of the extension to know you have to use it in replacement. Basically it would mean that extensions cannot override behaviors. They would just be able to add new components (like new Macros) but not modify behaviors at runtime.
But this only means we need to be able to change configuration without stopping the wiki and make it reload configs (might prove useful for other things as well), it doesn't mean we cannot do it "static".
If at some point we decide that the office implementation works better, we might consider changing the default implementation for the pdf component. This means that we'll change the hint of the FOP implementation from "default" to "fop", change the hint of the Office implementation from "office" to "default", and our new version of XE works great if people read the installation guide and properly configure the office connector. In practice we would have 2 choices with our current component impl.:
Choice 1: * Add 2 new implementations with hint1 and hint2 (hint1 being what was "default" before) * Keep the implementation with "default" hint but deprecate it and move it to legacy. Refactor it so that it delegates yo hint1 * Add a Provider to decide which impl to use based on whatever conditions we want
Choice 2: * Move "default" impl to "hint1" * Add "hint2" * Change "default" implementation to be a Composite that delegates to hint1 or hint2
But what about those that want to upgrade, but are happy with the older FOP implementation and don't want to add support for the office connector? Yes, in this case this is transparent for them (and it's a good thing in most caes!). This means they get autoupgrade to something better.
No, it means that for some reason we decided to change the underlying technology (e.g. change of licence), it doesn't mean that everybody is happy with the change.
They'll have to use patched versions of the two component implementations where their hints are reverted back to the old values. Easy? No. And even though "default" means "I don't care what the implementation does" It doesn't really mean this. We use "default" only when there's a single implementation. When there are more than 1 each one has a hint that is a qualifier to the implementation since there's no reason one is more default than the other.
, here it does matter a lot which implementation you're using. They have different requirements, and it's important to know if the implementation will require an office instance or not.
Saying that this won't happen since we're all really careful when designing our components is wishful thinking. We've refactored other more critical pieces of code than providing alternative implementations for a component, so we will find ourselves in situations where we'll have to switch from only one "default" implementation to several. I agree that we've refactored. And it has worked so far right? ;)
Designing our component manager to make it easy to transition is the right thing to do.
Still, my major problem is not about overrides, but about the semantics of "default" (or lack of it). This says nothing about the actual mechanisms behind the implementation, it just reflects the state of that particular component implementation: it's the default at the moment. Not caring what the implementation actually does works only when there is indeed just one possible implementation that is straight-forward. But in most cases, we do rely on another library that does the work for us, and libraries die, better alternatives come along, and changing that internal aspect of the implementation will sometimes be backwards incompatible, or have a different behavior. Sure, it does the same job, but it does it so differently that some will prefer to use the other approach. We have to let users decide which is their "default", and having multiple implementations with the "default" hint but different priorities is not very intuitive. Why not make everything default and remove hints completely if we don't really put any meaning into the hint?
This also means that we should only have components where there is a chance that another implementation might exist, because to the limit you can separate the interface from the implementation for any little piece of code that you write. I sort of feel you for this default thing, but at the same time, it's also a matter of education of the developer, which needs to make sure that they put a technology hint to the component, besides the default hint. The pb is that, as long as there is only one implementation, regardless of the technology it's based on, you also need to put the default hint since otherwise you'll have to hardcode the reference to the technology everywhere if you wanna use that service. so in this case default would mean 'this is the one that should be used because there's no other, you dumb CM that is not capable of seeing that'. This brings back some memories, but I don't know from what, about a system that was giving the available implementation regardless of its name. For example, we could make the CM return the only implementation, if only one exists, when asking for a component, regardless of its hint, so we don't have to put default everywhere. But then we need a strategy for the case when there are more.
And "default" adds another assumption: XWiki Enterprise is the ultimate target. Our defaults are the only ones that matter. As an example, all the *Configuration components have just one "default" implementation, which relies on xwiki.properties, XWiki.XWikiPreferences etc. Doesn't that tie the platform to the XWiki Enterprise wiki?
This not true in xwiki commons and rendering because I've made sure that we could use them outside of the XWiki Platform. They have default implementation that don't use XWiki Configuration module.
It's not a direct dependency visible at compilation time, it's worse, and invisible assumption about the final runtime. It's certainly not the default for other types of users that want to embed xwiki-commons or xwiki-platform components in a different type of end product. To me this isn't the default configuration, this is the default configuration used by XWiki Enterprise, thus my proposal of using something else as the generic component hint instead of "default". Ok thanks for the explanations. I understand better now what you mean.
Actually what you suggest could already be implemented using a best practice of always using Providers when you want a Component injected. In this manner by default you'll get the Generic Provider but anyone could implement a specific Provider implementation for it that would choose between various implementation based on whatever (a value in a META-INF/role-bindings.txt file, data from DB, etc).
<side note>Only issue with having Providers everywhere is that you get late verification of your system coherence since dependencies will be resolved only when they're used. OTOH this is a necessity in a fully-dynamic system ;)</side note>
Also, the notion of default doesn't always have a meaning. There are lots of cases when there are NO default. For example Macros or Transformations or…
Let's continue the discussion it's interesting :)
I'd like to review a bit the other Component system out there again to see what they do for this. It's important that they have support for this since we want to be able to switch to them one day. The 3 that I would review are: * Guice * CDI * OSGi
yes, we should learn from others. Maybe even use one? Thanks, Anca
Thanks -Vincent
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
On Fri, Apr 6, 2012 at 12:43 PM, Anca Luca <[email protected]> wrote:
I On 04/06/2012 09:35 AM, Vincent Massol wrote:
Hi Sergiu,
Note that below I'm going to play the devil's advocate since I think it's important we really think hard before changing anything and verify if our current implementation is not enough.
See below.
On Apr 5, 2012, at 8:44 PM, Sergiu Dumitriu wrote:
On 04/05/2012 12:51 PM, Anca Luca wrote:
On 04/05/2012 06:42 PM, Vincent Massol wrote:
Hi Sergiu,
On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
WDYT?
This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one).
To decide which implementation is used you use a priority order, as described on:
http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr...
I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it.
"...choosing the default between alternative implementations that should all **still be usable by themselves** is not possible"
The overrides mechanism allows to change which component will be returned for the "default" hint, but all the others will be invisible.
One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki.
Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default.
Exactly. For most of the "services" the XWiki platform currently has (storage, cache), we don't have a "default" implementation, but we rely on a kind of factory to lookup the configured default. That is an actual factory class in the case of the cache service, but just more code in the old XWiki.java class for the storage initialization.
Yep that's how it works.
A standard way of selecting the default means that we'll need less factories, and less code is always a good thing.
Yes but it has more limitation to what we have since with a proper Factory you can imagine all kind of logic to decide which implementation to use (hour of the day, whether the user is a premium user or not, etc).
BTW we do support Providers and the goal of the Provider is to be a factory for a given Role. So from now on, there should be no need to implement a Factory proper. Implementing a Provider is the new best practice for this.
Now, suppose one of the older components that had only one implementation, "default", gets alternative implementations, and we want to be able to allow more than one to be active in a wiki, and let the administrator decide which one should be considered the default. How can we approach this? The only way is indeed to have multiple hints, but last time I checked this resulted in more than one instance, even for @Singleton implementations.
Correct, ATM we support only one hint per implementation.
? I think Marius needed that for some wysiwyg stuff and we actually support multiple hints per implementation. It's just gonna give you a new instance for each hint, which in my view is a bug, not a missing feature.
https://github.com/xwiki/xwiki-platform/blob/master/xwiki-platform-core/xwik... but it's the old way to specify the hint. I don't think you can put two @Named or a list of names as the value of @Named. Thanks, Marius
Another approach is to deprecate the direct dependency declaration and instead introduce a factory that is responsible for selecting the default, but this breaks backwards compatibility.
Not completely true. Imagine you have (Role, "default") as your current component and you wish to be able to choose various implementation from now on. What you could do is this:
* Write a new component, a Factory, that overrides the current component, i.e. by using the same (Role, "default"). This factory will then delegate to whatever other implementation it wishes.
That's only possible if the public API of the CM allows you to grab overriden components (non-default defaults :) )
From the user of (Role, "default")'s POV he won't see a single change.
The "I don't care, just give me the default" strategy works as long as the component implementation is self-contained and doesn't involve data communication. Let's take an example, PDF export.
Currently the PDF export is only possible via FOP. If we were to convert the current interface + implementation class into a proper component, we'd name it "default", since it's the only one and who needs a factory for only one implementation.
Yes but we could also be thorough and instead implement a Provider<PDFExporter> instead.
People use it and they're happy because it just works. But we might soon add support for export via an office server. Suppose we want either FOP or Office to be usable as the default PDF export implementation. And suppose we'll want to keep both types of export active, so that we can use either one as the implementation for the default export of documents, the FOP implementation for exporting some kinds of documents like scientific articles, and the office connector for generating PDFs for presentations. Using the overrides mechanism we can only have one active at the same time, unless we introduce yet another factory which we can bypass using manual component lookup.
Based on your use case you'll need a UI to ask the user what he wants to export, i.e. either a "scientific article" or a "presentation" and from his choice you'll pick the right implementation. You could also try to guess that dynamically by looking at what is being exported but that'll require a Factory to hold that logic.
I know what you mean though: for some reason you don't want that to be dynamic and you wish it to be static.
There's a problem with dynamicity though. Imagine an extension that wants to replace an implementation. With your proposal the best practice would be to introduce a new Hint since the "default" is chosen statically at configuration time. So that wouldn't work. After you install extensions you'd need to stop the wiki, change the binding to the new implementation from the extension and restart it. Of course you'd need to read the documentation of the extension to know you have to use it in replacement. Basically it would mean that extensions cannot override behaviors. They would just be able to add new components (like new Macros) but not modify behaviors at runtime.
But this only means we need to be able to change configuration without stopping the wiki and make it reload configs (might prove useful for other things as well), it doesn't mean we cannot do it "static".
If at some point we decide that the office implementation works better, we might consider changing the default implementation for the pdf component. This means that we'll change the hint of the FOP implementation from "default" to "fop", change the hint of the Office implementation from "office" to "default", and our new version of XE works great if people read the installation guide and properly configure the office connector.
In practice we would have 2 choices with our current component impl.:
Choice 1: * Add 2 new implementations with hint1 and hint2 (hint1 being what was "default" before) * Keep the implementation with "default" hint but deprecate it and move it to legacy. Refactor it so that it delegates yo hint1 * Add a Provider to decide which impl to use based on whatever conditions we want
Choice 2: * Move "default" impl to "hint1" * Add "hint2" * Change "default" implementation to be a Composite that delegates to hint1 or hint2
But what about those that want to upgrade, but are happy with the older FOP implementation and don't want to add support for the office connector?
Yes, in this case this is transparent for them (and it's a good thing in most caes!). This means they get autoupgrade to something better.
No, it means that for some reason we decided to change the underlying technology (e.g. change of licence), it doesn't mean that everybody is happy with the change.
They'll have to use patched versions of the two component implementations where their hints are reverted back to the old values. Easy? No. And even though "default" means "I don't care what the implementation does"
It doesn't really mean this. We use "default" only when there's a single implementation. When there are more than 1 each one has a hint that is a qualifier to the implementation since there's no reason one is more default than the other.
, here it does matter a lot which implementation you're using. They have different requirements, and it's important to know if the implementation will require an office instance or not.
Saying that this won't happen since we're all really careful when designing our components is wishful thinking. We've refactored other more critical pieces of code than providing alternative implementations for a component, so we will find ourselves in situations where we'll have to switch from only one "default" implementation to several.
I agree that we've refactored. And it has worked so far right? ;)
Designing our component manager to make it easy to transition is the right thing to do.
Still, my major problem is not about overrides, but about the semantics of "default" (or lack of it). This says nothing about the actual mechanisms behind the implementation, it just reflects the state of that particular component implementation: it's the default at the moment. Not caring what the implementation actually does works only when there is indeed just one possible implementation that is straight-forward. But in most cases, we do rely on another library that does the work for us, and libraries die, better alternatives come along, and changing that internal aspect of the implementation will sometimes be backwards incompatible, or have a different behavior. Sure, it does the same job, but it does it so differently that some will prefer to use the other approach. We have to let users decide which is their "default", and having multiple implementations with the "default" hint but different priorities is not very intuitive. Why not make everything default and remove hints completely if we don't really put any meaning into the hint?
This also means that we should only have components where there is a chance that another implementation might exist, because to the limit you can separate the interface from the implementation for any little piece of code that you write.
I sort of feel you for this default thing, but at the same time, it's also a matter of education of the developer, which needs to make sure that they put a technology hint to the component, besides the default hint. The pb is that, as long as there is only one implementation, regardless of the technology it's based on, you also need to put the default hint since otherwise you'll have to hardcode the reference to the technology everywhere if you wanna use that service. so in this case default would mean 'this is the one that should be used because there's no other, you dumb CM that is not capable of seeing that'.
This brings back some memories, but I don't know from what, about a system that was giving the available implementation regardless of its name. For example, we could make the CM return the only implementation, if only one exists, when asking for a component, regardless of its hint, so we don't have to put default everywhere. But then we need a strategy for the case when there are more.
And "default" adds another assumption: XWiki Enterprise is the ultimate target. Our defaults are the only ones that matter. As an example, all the *Configuration components have just one "default" implementation, which relies on xwiki.properties, XWiki.XWikiPreferences etc. Doesn't that tie the platform to the XWiki Enterprise wiki?
This not true in xwiki commons and rendering because I've made sure that we could use them outside of the XWiki Platform. They have default implementation that don't use XWiki Configuration module.
It's not a direct dependency visible at compilation time, it's worse, and invisible assumption about the final runtime. It's certainly not the default for other types of users that want to embed xwiki-commons or xwiki-platform components in a different type of end product. To me this isn't the default configuration, this is the default configuration used by XWiki Enterprise, thus my proposal of using something else as the generic component hint instead of "default".
Ok thanks for the explanations. I understand better now what you mean.
Actually what you suggest could already be implemented using a best practice of always using Providers when you want a Component injected. In this manner by default you'll get the Generic Provider but anyone could implement a specific Provider implementation for it that would choose between various implementation based on whatever (a value in a META-INF/role-bindings.txt file, data from DB, etc).
<side note>Only issue with having Providers everywhere is that you get late verification of your system coherence since dependencies will be resolved only when they're used. OTOH this is a necessity in a fully-dynamic system ;)</side note>
Also, the notion of default doesn't always have a meaning. There are lots of cases when there are NO default. For example Macros or Transformations or…
Let's continue the discussion it's interesting :)
I'd like to review a bit the other Component system out there again to see what they do for this. It's important that they have support for this since we want to be able to switch to them one day. The 3 that I would review are: * Guice * CDI * OSGi
yes, we should learn from others. Maybe even use one?
Thanks, Anca
Thanks -Vincent
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
On Fri, Apr 6, 2012 at 12:02 PM, Marius Dumitru Florea <[email protected]> wrote:
On Fri, Apr 6, 2012 at 12:43 PM, Anca Luca <[email protected]> wrote:
I On 04/06/2012 09:35 AM, Vincent Massol wrote:
Hi Sergiu,
Note that below I'm going to play the devil's advocate since I think it's important we really think hard before changing anything and verify if our current implementation is not enough.
See below.
On Apr 5, 2012, at 8:44 PM, Sergiu Dumitriu wrote:
On 04/05/2012 12:51 PM, Anca Luca wrote:
On 04/05/2012 06:42 PM, Vincent Massol wrote:
Hi Sergiu,
On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
> Hi devs, > > Currently, requesting a component instance without a hint will look > for the implementation that uses the "default" hint, which makes it > difficult to change the implementation in an XWiki instance. Sure, it > is easy as long as all the implementations use the "default" hint, > but choosing the default between alternative implementations that > should all still be usable by themselves is not possible. > > Also, "default" is not really a good hint, since it describes the > state of the implementation, not the technology, the aspect that > makes it different from the others. It would be better to name each > implementation with a proper hint. > > I propose to define a mapping that can specify which hint is the > default for a component. In a text file, > META-INF/component-defaults.txt, we'll keep > componentinterface=defaulthint mappings. For example: > > com.xpn.xwiki.store.XWikiStoreInterface=hibernate > com.xpn.xwiki.store.migration.DataMigrationManager=hibernate > > And then, when we lookup the current storage implementation, we don't > need to check what is the configured hint in xwiki.cfg (or > xwiki.properties), we can just request the default implementation. > > If there's no mapping for a component, we'll continue to use the > "default" hint. > > I'm not sure where exactly to keep such files. We bundle a > components.txt file in each jar containing component implementations. > We could do the same for the components we consider the platform > defaults, and allow overrides in the > WEB-INF/classes/META-INF/component-defaults.txt file. Still, this > means that whenever platform defaults change, we need to keep another > special section in the release notes, to let users know about these > changes, so that they can manually revert to the old default if they > need to. > > In the future we could change existing components to give proper > hints instead of "default", where such a change is applicable. > > Another idea is to not use "default" at all, and instead go for a > generic "xwiki", "xe", "xwiki-platform" or something like that > whenever there's just one implementation for a component and we can't > find another hint to describe it. > > WDYT?
This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one).
To decide which implementation is used you use a priority order, as described on:
http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr...
I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it.
"...choosing the default between alternative implementations that should all **still be usable by themselves** is not possible"
The overrides mechanism allows to change which component will be returned for the "default" hint, but all the others will be invisible.
One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki.
Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default.
Exactly. For most of the "services" the XWiki platform currently has (storage, cache), we don't have a "default" implementation, but we rely on a kind of factory to lookup the configured default. That is an actual factory class in the case of the cache service, but just more code in the old XWiki.java class for the storage initialization.
Yep that's how it works.
A standard way of selecting the default means that we'll need less factories, and less code is always a good thing.
Yes but it has more limitation to what we have since with a proper Factory you can imagine all kind of logic to decide which implementation to use (hour of the day, whether the user is a premium user or not, etc).
BTW we do support Providers and the goal of the Provider is to be a factory for a given Role. So from now on, there should be no need to implement a Factory proper. Implementing a Provider is the new best practice for this.
Now, suppose one of the older components that had only one implementation, "default", gets alternative implementations, and we want to be able to allow more than one to be active in a wiki, and let the administrator decide which one should be considered the default. How can we approach this? The only way is indeed to have multiple hints, but last time I checked this resulted in more than one instance, even for @Singleton implementations.
Correct, ATM we support only one hint per implementation.
? I think Marius needed that for some wysiwyg stuff and we actually support multiple hints per implementation. It's just gonna give you a new instance for each hint, which in my view is a bug, not a missing feature.
https://github.com/xwiki/xwiki-platform/blob/master/xwiki-platform-core/xwik...
but it's the old way to specify the hint. I don't think you can put two @Named or a list of names as the value of @Named.
Well you can put several time an annotation but I don't think we take all of then into account (but that's just a choice, we could decide to take all of them).
Thanks, Marius
Another approach is to deprecate the direct dependency declaration and instead introduce a factory that is responsible for selecting the default, but this breaks backwards compatibility.
Not completely true. Imagine you have (Role, "default") as your current component and you wish to be able to choose various implementation from now on. What you could do is this:
* Write a new component, a Factory, that overrides the current component, i.e. by using the same (Role, "default"). This factory will then delegate to whatever other implementation it wishes.
That's only possible if the public API of the CM allows you to grab overriden components (non-default defaults :) )
From the user of (Role, "default")'s POV he won't see a single change.
The "I don't care, just give me the default" strategy works as long as the component implementation is self-contained and doesn't involve data communication. Let's take an example, PDF export.
Currently the PDF export is only possible via FOP. If we were to convert the current interface + implementation class into a proper component, we'd name it "default", since it's the only one and who needs a factory for only one implementation.
Yes but we could also be thorough and instead implement a Provider<PDFExporter> instead.
People use it and they're happy because it just works. But we might soon add support for export via an office server. Suppose we want either FOP or Office to be usable as the default PDF export implementation. And suppose we'll want to keep both types of export active, so that we can use either one as the implementation for the default export of documents, the FOP implementation for exporting some kinds of documents like scientific articles, and the office connector for generating PDFs for presentations. Using the overrides mechanism we can only have one active at the same time, unless we introduce yet another factory which we can bypass using manual component lookup.
Based on your use case you'll need a UI to ask the user what he wants to export, i.e. either a "scientific article" or a "presentation" and from his choice you'll pick the right implementation. You could also try to guess that dynamically by looking at what is being exported but that'll require a Factory to hold that logic.
I know what you mean though: for some reason you don't want that to be dynamic and you wish it to be static.
There's a problem with dynamicity though. Imagine an extension that wants to replace an implementation. With your proposal the best practice would be to introduce a new Hint since the "default" is chosen statically at configuration time. So that wouldn't work. After you install extensions you'd need to stop the wiki, change the binding to the new implementation from the extension and restart it. Of course you'd need to read the documentation of the extension to know you have to use it in replacement. Basically it would mean that extensions cannot override behaviors. They would just be able to add new components (like new Macros) but not modify behaviors at runtime.
But this only means we need to be able to change configuration without stopping the wiki and make it reload configs (might prove useful for other things as well), it doesn't mean we cannot do it "static".
If at some point we decide that the office implementation works better, we might consider changing the default implementation for the pdf component. This means that we'll change the hint of the FOP implementation from "default" to "fop", change the hint of the Office implementation from "office" to "default", and our new version of XE works great if people read the installation guide and properly configure the office connector.
In practice we would have 2 choices with our current component impl.:
Choice 1: * Add 2 new implementations with hint1 and hint2 (hint1 being what was "default" before) * Keep the implementation with "default" hint but deprecate it and move it to legacy. Refactor it so that it delegates yo hint1 * Add a Provider to decide which impl to use based on whatever conditions we want
Choice 2: * Move "default" impl to "hint1" * Add "hint2" * Change "default" implementation to be a Composite that delegates to hint1 or hint2
But what about those that want to upgrade, but are happy with the older FOP implementation and don't want to add support for the office connector?
Yes, in this case this is transparent for them (and it's a good thing in most caes!). This means they get autoupgrade to something better.
No, it means that for some reason we decided to change the underlying technology (e.g. change of licence), it doesn't mean that everybody is happy with the change.
They'll have to use patched versions of the two component implementations where their hints are reverted back to the old values. Easy? No. And even though "default" means "I don't care what the implementation does"
It doesn't really mean this. We use "default" only when there's a single implementation. When there are more than 1 each one has a hint that is a qualifier to the implementation since there's no reason one is more default than the other.
, here it does matter a lot which implementation you're using. They have different requirements, and it's important to know if the implementation will require an office instance or not.
Saying that this won't happen since we're all really careful when designing our components is wishful thinking. We've refactored other more critical pieces of code than providing alternative implementations for a component, so we will find ourselves in situations where we'll have to switch from only one "default" implementation to several.
I agree that we've refactored. And it has worked so far right? ;)
Designing our component manager to make it easy to transition is the right thing to do.
Still, my major problem is not about overrides, but about the semantics of "default" (or lack of it). This says nothing about the actual mechanisms behind the implementation, it just reflects the state of that particular component implementation: it's the default at the moment. Not caring what the implementation actually does works only when there is indeed just one possible implementation that is straight-forward. But in most cases, we do rely on another library that does the work for us, and libraries die, better alternatives come along, and changing that internal aspect of the implementation will sometimes be backwards incompatible, or have a different behavior. Sure, it does the same job, but it does it so differently that some will prefer to use the other approach. We have to let users decide which is their "default", and having multiple implementations with the "default" hint but different priorities is not very intuitive. Why not make everything default and remove hints completely if we don't really put any meaning into the hint?
This also means that we should only have components where there is a chance that another implementation might exist, because to the limit you can separate the interface from the implementation for any little piece of code that you write.
I sort of feel you for this default thing, but at the same time, it's also a matter of education of the developer, which needs to make sure that they put a technology hint to the component, besides the default hint. The pb is that, as long as there is only one implementation, regardless of the technology it's based on, you also need to put the default hint since otherwise you'll have to hardcode the reference to the technology everywhere if you wanna use that service. so in this case default would mean 'this is the one that should be used because there's no other, you dumb CM that is not capable of seeing that'.
This brings back some memories, but I don't know from what, about a system that was giving the available implementation regardless of its name. For example, we could make the CM return the only implementation, if only one exists, when asking for a component, regardless of its hint, so we don't have to put default everywhere. But then we need a strategy for the case when there are more.
And "default" adds another assumption: XWiki Enterprise is the ultimate target. Our defaults are the only ones that matter. As an example, all the *Configuration components have just one "default" implementation, which relies on xwiki.properties, XWiki.XWikiPreferences etc. Doesn't that tie the platform to the XWiki Enterprise wiki?
This not true in xwiki commons and rendering because I've made sure that we could use them outside of the XWiki Platform. They have default implementation that don't use XWiki Configuration module.
It's not a direct dependency visible at compilation time, it's worse, and invisible assumption about the final runtime. It's certainly not the default for other types of users that want to embed xwiki-commons or xwiki-platform components in a different type of end product. To me this isn't the default configuration, this is the default configuration used by XWiki Enterprise, thus my proposal of using something else as the generic component hint instead of "default".
Ok thanks for the explanations. I understand better now what you mean.
Actually what you suggest could already be implemented using a best practice of always using Providers when you want a Component injected. In this manner by default you'll get the Generic Provider but anyone could implement a specific Provider implementation for it that would choose between various implementation based on whatever (a value in a META-INF/role-bindings.txt file, data from DB, etc).
<side note>Only issue with having Providers everywhere is that you get late verification of your system coherence since dependencies will be resolved only when they're used. OTOH this is a necessity in a fully-dynamic system ;)</side note>
Also, the notion of default doesn't always have a meaning. There are lots of cases when there are NO default. For example Macros or Transformations or…
Let's continue the discussion it's interesting :)
I'd like to review a bit the other Component system out there again to see what they do for this. It's important that they have support for this since we want to be able to switch to them one day. The 3 that I would review are: * Guice * CDI * OSGi
yes, we should learn from others. Maybe even use one?
Thanks, Anca
Thanks -Vincent
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
-- Thomas Mortagne
On Apr 6, 2012, at 12:11 PM, Thomas Mortagne wrote:
On Fri, Apr 6, 2012 at 12:02 PM, Marius Dumitru Florea <[email protected]> wrote:
On Fri, Apr 6, 2012 at 12:43 PM, Anca Luca <[email protected]> wrote:
I On 04/06/2012 09:35 AM, Vincent Massol wrote:
Hi Sergiu,
Note that below I'm going to play the devil's advocate since I think it's important we really think hard before changing anything and verify if our current implementation is not enough.
See below.
On Apr 5, 2012, at 8:44 PM, Sergiu Dumitriu wrote:
On 04/05/2012 12:51 PM, Anca Luca wrote:
On 04/05/2012 06:42 PM, Vincent Massol wrote: > > Hi Sergiu, > > On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote: > >> Hi devs, >> >> Currently, requesting a component instance without a hint will look >> for the implementation that uses the "default" hint, which makes it >> difficult to change the implementation in an XWiki instance. Sure, it >> is easy as long as all the implementations use the "default" hint, >> but choosing the default between alternative implementations that >> should all still be usable by themselves is not possible. >> >> Also, "default" is not really a good hint, since it describes the >> state of the implementation, not the technology, the aspect that >> makes it different from the others. It would be better to name each >> implementation with a proper hint. >> >> I propose to define a mapping that can specify which hint is the >> default for a component. In a text file, >> META-INF/component-defaults.txt, we'll keep >> componentinterface=defaulthint mappings. For example: >> >> com.xpn.xwiki.store.XWikiStoreInterface=hibernate >> com.xpn.xwiki.store.migration.DataMigrationManager=hibernate >> >> And then, when we lookup the current storage implementation, we don't >> need to check what is the configured hint in xwiki.cfg (or >> xwiki.properties), we can just request the default implementation. >> >> If there's no mapping for a component, we'll continue to use the >> "default" hint. >> >> I'm not sure where exactly to keep such files. We bundle a >> components.txt file in each jar containing component implementations. >> We could do the same for the components we consider the platform >> defaults, and allow overrides in the >> WEB-INF/classes/META-INF/component-defaults.txt file. Still, this >> means that whenever platform defaults change, we need to keep another >> special section in the release notes, to let users know about these >> changes, so that they can manually revert to the old default if they >> need to. >> >> In the future we could change existing components to give proper >> hints instead of "default", where such a change is applicable. >> >> Another idea is to not use "default" at all, and instead go for a >> generic "xwiki", "xe", "xwiki-platform" or something like that >> whenever there's just one implementation for a component and we can't >> find another hint to describe it. >> >> WDYT? > > This is not really how it's been designed ATM. Whenever you wish to > use a different implementation of a component you use a component > implementation with the same role and same hint. You then make it > available in your classpath. (Of course you can also do this at > runtime simply by registering a new implementation over the old one). > > To decide which implementation is used you use a priority order, as > described on: > > http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr... > > > I'd be curious to know your exact use case and understand why the > current mechanism doesn't work for it.
"...choosing the default between alternative implementations that should all **still be usable by themselves** is not possible"
The overrides mechanism allows to change which component will be returned for the "default" hint, but all the others will be invisible.
One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki.
Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default.
Exactly. For most of the "services" the XWiki platform currently has (storage, cache), we don't have a "default" implementation, but we rely on a kind of factory to lookup the configured default. That is an actual factory class in the case of the cache service, but just more code in the old XWiki.java class for the storage initialization.
Yep that's how it works.
A standard way of selecting the default means that we'll need less factories, and less code is always a good thing.
Yes but it has more limitation to what we have since with a proper Factory you can imagine all kind of logic to decide which implementation to use (hour of the day, whether the user is a premium user or not, etc).
BTW we do support Providers and the goal of the Provider is to be a factory for a given Role. So from now on, there should be no need to implement a Factory proper. Implementing a Provider is the new best practice for this.
Now, suppose one of the older components that had only one implementation, "default", gets alternative implementations, and we want to be able to allow more than one to be active in a wiki, and let the administrator decide which one should be considered the default. How can we approach this? The only way is indeed to have multiple hints, but last time I checked this resulted in more than one instance, even for @Singleton implementations.
Correct, ATM we support only one hint per implementation.
? I think Marius needed that for some wysiwyg stuff and we actually support multiple hints per implementation. It's just gonna give you a new instance for each hint, which in my view is a bug, not a missing feature.
https://github.com/xwiki/xwiki-platform/blob/master/xwiki-platform-core/xwik...
but it's the old way to specify the hint. I don't think you can put two @Named or a list of names as the value of @Named.
Well you can put several time an annotation but I don't think we take all of then into account (but that's just a choice, we could decide to take all of them).
No I don't think it's completely our choice. We have to be following the JSR330 specification, i.e. when your component is used in a different component manager (with Guice for example) it has to work. We would need to check if that's the case but I doubt it. Thanks -Vincent
Thanks, Marius
Another approach is to deprecate the direct dependency declaration and instead introduce a factory that is responsible for selecting the default, but this breaks backwards compatibility.
Not completely true. Imagine you have (Role, "default") as your current component and you wish to be able to choose various implementation from now on. What you could do is this:
* Write a new component, a Factory, that overrides the current component, i.e. by using the same (Role, "default"). This factory will then delegate to whatever other implementation it wishes.
That's only possible if the public API of the CM allows you to grab overriden components (non-default defaults :) )
From the user of (Role, "default")'s POV he won't see a single change.
The "I don't care, just give me the default" strategy works as long as the component implementation is self-contained and doesn't involve data communication. Let's take an example, PDF export.
Currently the PDF export is only possible via FOP. If we were to convert the current interface + implementation class into a proper component, we'd name it "default", since it's the only one and who needs a factory for only one implementation.
Yes but we could also be thorough and instead implement a Provider<PDFExporter> instead.
People use it and they're happy because it just works. But we might soon add support for export via an office server. Suppose we want either FOP or Office to be usable as the default PDF export implementation. And suppose we'll want to keep both types of export active, so that we can use either one as the implementation for the default export of documents, the FOP implementation for exporting some kinds of documents like scientific articles, and the office connector for generating PDFs for presentations. Using the overrides mechanism we can only have one active at the same time, unless we introduce yet another factory which we can bypass using manual component lookup.
Based on your use case you'll need a UI to ask the user what he wants to export, i.e. either a "scientific article" or a "presentation" and from his choice you'll pick the right implementation. You could also try to guess that dynamically by looking at what is being exported but that'll require a Factory to hold that logic.
I know what you mean though: for some reason you don't want that to be dynamic and you wish it to be static.
There's a problem with dynamicity though. Imagine an extension that wants to replace an implementation. With your proposal the best practice would be to introduce a new Hint since the "default" is chosen statically at configuration time. So that wouldn't work. After you install extensions you'd need to stop the wiki, change the binding to the new implementation from the extension and restart it. Of course you'd need to read the documentation of the extension to know you have to use it in replacement. Basically it would mean that extensions cannot override behaviors. They would just be able to add new components (like new Macros) but not modify behaviors at runtime.
But this only means we need to be able to change configuration without stopping the wiki and make it reload configs (might prove useful for other things as well), it doesn't mean we cannot do it "static".
If at some point we decide that the office implementation works better, we might consider changing the default implementation for the pdf component. This means that we'll change the hint of the FOP implementation from "default" to "fop", change the hint of the Office implementation from "office" to "default", and our new version of XE works great if people read the installation guide and properly configure the office connector.
In practice we would have 2 choices with our current component impl.:
Choice 1: * Add 2 new implementations with hint1 and hint2 (hint1 being what was "default" before) * Keep the implementation with "default" hint but deprecate it and move it to legacy. Refactor it so that it delegates yo hint1 * Add a Provider to decide which impl to use based on whatever conditions we want
Choice 2: * Move "default" impl to "hint1" * Add "hint2" * Change "default" implementation to be a Composite that delegates to hint1 or hint2
But what about those that want to upgrade, but are happy with the older FOP implementation and don't want to add support for the office connector?
Yes, in this case this is transparent for them (and it's a good thing in most caes!). This means they get autoupgrade to something better.
No, it means that for some reason we decided to change the underlying technology (e.g. change of licence), it doesn't mean that everybody is happy with the change.
They'll have to use patched versions of the two component implementations where their hints are reverted back to the old values. Easy? No. And even though "default" means "I don't care what the implementation does"
It doesn't really mean this. We use "default" only when there's a single implementation. When there are more than 1 each one has a hint that is a qualifier to the implementation since there's no reason one is more default than the other.
, here it does matter a lot which implementation you're using. They have different requirements, and it's important to know if the implementation will require an office instance or not.
Saying that this won't happen since we're all really careful when designing our components is wishful thinking. We've refactored other more critical pieces of code than providing alternative implementations for a component, so we will find ourselves in situations where we'll have to switch from only one "default" implementation to several.
I agree that we've refactored. And it has worked so far right? ;)
Designing our component manager to make it easy to transition is the right thing to do.
Still, my major problem is not about overrides, but about the semantics of "default" (or lack of it). This says nothing about the actual mechanisms behind the implementation, it just reflects the state of that particular component implementation: it's the default at the moment. Not caring what the implementation actually does works only when there is indeed just one possible implementation that is straight-forward. But in most cases, we do rely on another library that does the work for us, and libraries die, better alternatives come along, and changing that internal aspect of the implementation will sometimes be backwards incompatible, or have a different behavior. Sure, it does the same job, but it does it so differently that some will prefer to use the other approach. We have to let users decide which is their "default", and having multiple implementations with the "default" hint but different priorities is not very intuitive. Why not make everything default and remove hints completely if we don't really put any meaning into the hint?
This also means that we should only have components where there is a chance that another implementation might exist, because to the limit you can separate the interface from the implementation for any little piece of code that you write.
I sort of feel you for this default thing, but at the same time, it's also a matter of education of the developer, which needs to make sure that they put a technology hint to the component, besides the default hint. The pb is that, as long as there is only one implementation, regardless of the technology it's based on, you also need to put the default hint since otherwise you'll have to hardcode the reference to the technology everywhere if you wanna use that service. so in this case default would mean 'this is the one that should be used because there's no other, you dumb CM that is not capable of seeing that'.
This brings back some memories, but I don't know from what, about a system that was giving the available implementation regardless of its name. For example, we could make the CM return the only implementation, if only one exists, when asking for a component, regardless of its hint, so we don't have to put default everywhere. But then we need a strategy for the case when there are more.
And "default" adds another assumption: XWiki Enterprise is the ultimate target. Our defaults are the only ones that matter. As an example, all the *Configuration components have just one "default" implementation, which relies on xwiki.properties, XWiki.XWikiPreferences etc. Doesn't that tie the platform to the XWiki Enterprise wiki?
This not true in xwiki commons and rendering because I've made sure that we could use them outside of the XWiki Platform. They have default implementation that don't use XWiki Configuration module.
It's not a direct dependency visible at compilation time, it's worse, and invisible assumption about the final runtime. It's certainly not the default for other types of users that want to embed xwiki-commons or xwiki-platform components in a different type of end product. To me this isn't the default configuration, this is the default configuration used by XWiki Enterprise, thus my proposal of using something else as the generic component hint instead of "default".
Ok thanks for the explanations. I understand better now what you mean.
Actually what you suggest could already be implemented using a best practice of always using Providers when you want a Component injected. In this manner by default you'll get the Generic Provider but anyone could implement a specific Provider implementation for it that would choose between various implementation based on whatever (a value in a META-INF/role-bindings.txt file, data from DB, etc).
<side note>Only issue with having Providers everywhere is that you get late verification of your system coherence since dependencies will be resolved only when they're used. OTOH this is a necessity in a fully-dynamic system ;)</side note>
Also, the notion of default doesn't always have a meaning. There are lots of cases when there are NO default. For example Macros or Transformations or…
Let's continue the discussion it's interesting :)
I'd like to review a bit the other Component system out there again to see what they do for this. It's important that they have support for this since we want to be able to switch to them one day. The 3 that I would review are: * Guice * CDI * OSGi
yes, we should learn from others. Maybe even use one?
Thanks, Anca
Thanks -Vincent
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
-- Thomas Mortagne _______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
On Fri, Apr 6, 2012 at 12:37 PM, Vincent Massol <[email protected]> wrote:
On Apr 6, 2012, at 12:11 PM, Thomas Mortagne wrote:
On Fri, Apr 6, 2012 at 12:02 PM, Marius Dumitru Florea <[email protected]> wrote:
On Fri, Apr 6, 2012 at 12:43 PM, Anca Luca <[email protected]> wrote:
I On 04/06/2012 09:35 AM, Vincent Massol wrote:
Hi Sergiu,
Note that below I'm going to play the devil's advocate since I think it's important we really think hard before changing anything and verify if our current implementation is not enough.
See below.
On Apr 5, 2012, at 8:44 PM, Sergiu Dumitriu wrote:
On 04/05/2012 12:51 PM, Anca Luca wrote: > > On 04/05/2012 06:42 PM, Vincent Massol wrote: >> >> Hi Sergiu, >> >> On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote: >> >>> Hi devs, >>> >>> Currently, requesting a component instance without a hint will look >>> for the implementation that uses the "default" hint, which makes it >>> difficult to change the implementation in an XWiki instance. Sure, it >>> is easy as long as all the implementations use the "default" hint, >>> but choosing the default between alternative implementations that >>> should all still be usable by themselves is not possible. >>> >>> Also, "default" is not really a good hint, since it describes the >>> state of the implementation, not the technology, the aspect that >>> makes it different from the others. It would be better to name each >>> implementation with a proper hint. >>> >>> I propose to define a mapping that can specify which hint is the >>> default for a component. In a text file, >>> META-INF/component-defaults.txt, we'll keep >>> componentinterface=defaulthint mappings. For example: >>> >>> com.xpn.xwiki.store.XWikiStoreInterface=hibernate >>> com.xpn.xwiki.store.migration.DataMigrationManager=hibernate >>> >>> And then, when we lookup the current storage implementation, we don't >>> need to check what is the configured hint in xwiki.cfg (or >>> xwiki.properties), we can just request the default implementation. >>> >>> If there's no mapping for a component, we'll continue to use the >>> "default" hint. >>> >>> I'm not sure where exactly to keep such files. We bundle a >>> components.txt file in each jar containing component implementations. >>> We could do the same for the components we consider the platform >>> defaults, and allow overrides in the >>> WEB-INF/classes/META-INF/component-defaults.txt file. Still, this >>> means that whenever platform defaults change, we need to keep another >>> special section in the release notes, to let users know about these >>> changes, so that they can manually revert to the old default if they >>> need to. >>> >>> In the future we could change existing components to give proper >>> hints instead of "default", where such a change is applicable. >>> >>> Another idea is to not use "default" at all, and instead go for a >>> generic "xwiki", "xe", "xwiki-platform" or something like that >>> whenever there's just one implementation for a component and we can't >>> find another hint to describe it. >>> >>> WDYT? >> >> This is not really how it's been designed ATM. Whenever you wish to >> use a different implementation of a component you use a component >> implementation with the same role and same hint. You then make it >> available in your classpath. (Of course you can also do this at >> runtime simply by registering a new implementation over the old one). >> >> To decide which implementation is used you use a priority order, as >> described on: >> >> http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr... >> >> >> I'd be curious to know your exact use case and understand why the >> current mechanism doesn't work for it.
"...choosing the default between alternative implementations that should all **still be usable by themselves** is not possible"
The overrides mechanism allows to change which component will be returned for the "default" hint, but all the others will be invisible.
> One usecase I see is that you have multiple implementations and you want > to change the default one for a specific running instance of xwiki. > > Overwrite mechanism only allows you to say which impl should be used > from the _components with the same hint_. However, you cannot change the > hint of a component at configuration time, so if you have a standard > distr of xwiki and you want to use ldap authentication, let's say (if > only auth was impl with components), unless you do some java to add the > default hint to the ldap implementation and then to specify that this > one has priority over all the default ones, I don't see how you can > re-wire the default.
Exactly. For most of the "services" the XWiki platform currently has (storage, cache), we don't have a "default" implementation, but we rely on a kind of factory to lookup the configured default. That is an actual factory class in the case of the cache service, but just more code in the old XWiki.java class for the storage initialization.
Yep that's how it works.
A standard way of selecting the default means that we'll need less factories, and less code is always a good thing.
Yes but it has more limitation to what we have since with a proper Factory you can imagine all kind of logic to decide which implementation to use (hour of the day, whether the user is a premium user or not, etc).
BTW we do support Providers and the goal of the Provider is to be a factory for a given Role. So from now on, there should be no need to implement a Factory proper. Implementing a Provider is the new best practice for this.
Now, suppose one of the older components that had only one implementation, "default", gets alternative implementations, and we want to be able to allow more than one to be active in a wiki, and let the administrator decide which one should be considered the default. How can we approach this? The only way is indeed to have multiple hints, but last time I checked this resulted in more than one instance, even for @Singleton implementations.
Correct, ATM we support only one hint per implementation.
? I think Marius needed that for some wysiwyg stuff and we actually support multiple hints per implementation. It's just gonna give you a new instance for each hint, which in my view is a bug, not a missing feature.
https://github.com/xwiki/xwiki-platform/blob/master/xwiki-platform-core/xwik...
but it's the old way to specify the hint. I don't think you can put two @Named or a list of names as the value of @Named.
Well you can put several time an annotation but I don't think we take all of then into account (but that's just a choice, we could decide to take all of them).
No I don't think it's completely our choice. We have to be following the JSR330 specification, i.e. when your component is used in a different component manager (with Guice for example) it has to work. We would need to check if that's the case but I doubt it.
JSR330 only define injection now how you register a component instance. Anyway I already said we can't do whatever we want and that there is a lot of things we did not do because it was not supported in Plexus when we started or other components managers now.
Thanks -Vincent
Thanks, Marius
Another approach is to deprecate the direct dependency declaration and instead introduce a factory that is responsible for selecting the default, but this breaks backwards compatibility.
Not completely true. Imagine you have (Role, "default") as your current component and you wish to be able to choose various implementation from now on. What you could do is this:
* Write a new component, a Factory, that overrides the current component, i.e. by using the same (Role, "default"). This factory will then delegate to whatever other implementation it wishes.
That's only possible if the public API of the CM allows you to grab overriden components (non-default defaults :) )
From the user of (Role, "default")'s POV he won't see a single change.
The "I don't care, just give me the default" strategy works as long as the component implementation is self-contained and doesn't involve data communication. Let's take an example, PDF export.
Currently the PDF export is only possible via FOP. If we were to convert the current interface + implementation class into a proper component, we'd name it "default", since it's the only one and who needs a factory for only one implementation.
Yes but we could also be thorough and instead implement a Provider<PDFExporter> instead.
People use it and they're happy because it just works. But we might soon add support for export via an office server. Suppose we want either FOP or Office to be usable as the default PDF export implementation. And suppose we'll want to keep both types of export active, so that we can use either one as the implementation for the default export of documents, the FOP implementation for exporting some kinds of documents like scientific articles, and the office connector for generating PDFs for presentations. Using the overrides mechanism we can only have one active at the same time, unless we introduce yet another factory which we can bypass using manual component lookup.
Based on your use case you'll need a UI to ask the user what he wants to export, i.e. either a "scientific article" or a "presentation" and from his choice you'll pick the right implementation. You could also try to guess that dynamically by looking at what is being exported but that'll require a Factory to hold that logic.
I know what you mean though: for some reason you don't want that to be dynamic and you wish it to be static.
There's a problem with dynamicity though. Imagine an extension that wants to replace an implementation. With your proposal the best practice would be to introduce a new Hint since the "default" is chosen statically at configuration time. So that wouldn't work. After you install extensions you'd need to stop the wiki, change the binding to the new implementation from the extension and restart it. Of course you'd need to read the documentation of the extension to know you have to use it in replacement. Basically it would mean that extensions cannot override behaviors. They would just be able to add new components (like new Macros) but not modify behaviors at runtime.
But this only means we need to be able to change configuration without stopping the wiki and make it reload configs (might prove useful for other things as well), it doesn't mean we cannot do it "static".
If at some point we decide that the office implementation works better, we might consider changing the default implementation for the pdf component. This means that we'll change the hint of the FOP implementation from "default" to "fop", change the hint of the Office implementation from "office" to "default", and our new version of XE works great if people read the installation guide and properly configure the office connector.
In practice we would have 2 choices with our current component impl.:
Choice 1: * Add 2 new implementations with hint1 and hint2 (hint1 being what was "default" before) * Keep the implementation with "default" hint but deprecate it and move it to legacy. Refactor it so that it delegates yo hint1 * Add a Provider to decide which impl to use based on whatever conditions we want
Choice 2: * Move "default" impl to "hint1" * Add "hint2" * Change "default" implementation to be a Composite that delegates to hint1 or hint2
But what about those that want to upgrade, but are happy with the older FOP implementation and don't want to add support for the office connector?
Yes, in this case this is transparent for them (and it's a good thing in most caes!). This means they get autoupgrade to something better.
No, it means that for some reason we decided to change the underlying technology (e.g. change of licence), it doesn't mean that everybody is happy with the change.
They'll have to use patched versions of the two component implementations where their hints are reverted back to the old values. Easy? No. And even though "default" means "I don't care what the implementation does"
It doesn't really mean this. We use "default" only when there's a single implementation. When there are more than 1 each one has a hint that is a qualifier to the implementation since there's no reason one is more default than the other.
, here it does matter a lot which implementation you're using. They have different requirements, and it's important to know if the implementation will require an office instance or not.
Saying that this won't happen since we're all really careful when designing our components is wishful thinking. We've refactored other more critical pieces of code than providing alternative implementations for a component, so we will find ourselves in situations where we'll have to switch from only one "default" implementation to several.
I agree that we've refactored. And it has worked so far right? ;)
Designing our component manager to make it easy to transition is the right thing to do.
Still, my major problem is not about overrides, but about the semantics of "default" (or lack of it). This says nothing about the actual mechanisms behind the implementation, it just reflects the state of that particular component implementation: it's the default at the moment. Not caring what the implementation actually does works only when there is indeed just one possible implementation that is straight-forward. But in most cases, we do rely on another library that does the work for us, and libraries die, better alternatives come along, and changing that internal aspect of the implementation will sometimes be backwards incompatible, or have a different behavior. Sure, it does the same job, but it does it so differently that some will prefer to use the other approach. We have to let users decide which is their "default", and having multiple implementations with the "default" hint but different priorities is not very intuitive. Why not make everything default and remove hints completely if we don't really put any meaning into the hint?
This also means that we should only have components where there is a chance that another implementation might exist, because to the limit you can separate the interface from the implementation for any little piece of code that you write.
I sort of feel you for this default thing, but at the same time, it's also a matter of education of the developer, which needs to make sure that they put a technology hint to the component, besides the default hint. The pb is that, as long as there is only one implementation, regardless of the technology it's based on, you also need to put the default hint since otherwise you'll have to hardcode the reference to the technology everywhere if you wanna use that service. so in this case default would mean 'this is the one that should be used because there's no other, you dumb CM that is not capable of seeing that'.
This brings back some memories, but I don't know from what, about a system that was giving the available implementation regardless of its name. For example, we could make the CM return the only implementation, if only one exists, when asking for a component, regardless of its hint, so we don't have to put default everywhere. But then we need a strategy for the case when there are more.
And "default" adds another assumption: XWiki Enterprise is the ultimate target. Our defaults are the only ones that matter. As an example, all the *Configuration components have just one "default" implementation, which relies on xwiki.properties, XWiki.XWikiPreferences etc. Doesn't that tie the platform to the XWiki Enterprise wiki?
This not true in xwiki commons and rendering because I've made sure that we could use them outside of the XWiki Platform. They have default implementation that don't use XWiki Configuration module.
It's not a direct dependency visible at compilation time, it's worse, and invisible assumption about the final runtime. It's certainly not the default for other types of users that want to embed xwiki-commons or xwiki-platform components in a different type of end product. To me this isn't the default configuration, this is the default configuration used by XWiki Enterprise, thus my proposal of using something else as the generic component hint instead of "default".
Ok thanks for the explanations. I understand better now what you mean.
Actually what you suggest could already be implemented using a best practice of always using Providers when you want a Component injected. In this manner by default you'll get the Generic Provider but anyone could implement a specific Provider implementation for it that would choose between various implementation based on whatever (a value in a META-INF/role-bindings.txt file, data from DB, etc).
<side note>Only issue with having Providers everywhere is that you get late verification of your system coherence since dependencies will be resolved only when they're used. OTOH this is a necessity in a fully-dynamic system ;)</side note>
Also, the notion of default doesn't always have a meaning. There are lots of cases when there are NO default. For example Macros or Transformations or…
Let's continue the discussion it's interesting :)
I'd like to review a bit the other Component system out there again to see what they do for this. It's important that they have support for this since we want to be able to switch to them one day. The 3 that I would review are: * Guice * CDI * OSGi
yes, we should learn from others. Maybe even use one?
Thanks, Anca
Thanks -Vincent
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
-- Thomas Mortagne _______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
-- Thomas Mortagne
On Apr 6, 2012, at 11:43 AM, Anca Luca wrote:
I On 04/06/2012 09:35 AM, Vincent Massol wrote:
Hi Sergiu,
Note that below I'm going to play the devil's advocate since I think it's important we really think hard before changing anything and verify if our current implementation is not enough.
See below.
On Apr 5, 2012, at 8:44 PM, Sergiu Dumitriu wrote:
On 04/05/2012 12:51 PM, Anca Luca wrote:
On 04/05/2012 06:42 PM, Vincent Massol wrote:
Hi Sergiu,
On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
WDYT? This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one).
To decide which implementation is used you use a priority order, as described on: http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr...
I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it. "...choosing the default between alternative implementations that should all **still be usable by themselves** is not possible"
The overrides mechanism allows to change which component will be returned for the "default" hint, but all the others will be invisible.
One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki.
Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default. Exactly. For most of the "services" the XWiki platform currently has (storage, cache), we don't have a "default" implementation, but we rely on a kind of factory to lookup the configured default. That is an actual factory class in the case of the cache service, but just more code in the old XWiki.java class for the storage initialization. Yep that's how it works.
A standard way of selecting the default means that we'll need less factories, and less code is always a good thing. Yes but it has more limitation to what we have since with a proper Factory you can imagine all kind of logic to decide which implementation to use (hour of the day, whether the user is a premium user or not, etc).
BTW we do support Providers and the goal of the Provider is to be a factory for a given Role. So from now on, there should be no need to implement a Factory proper. Implementing a Provider is the new best practice for this.
Now, suppose one of the older components that had only one implementation, "default", gets alternative implementations, and we want to be able to allow more than one to be active in a wiki, and let the administrator decide which one should be considered the default. How can we approach this? The only way is indeed to have multiple hints, but last time I checked this resulted in more than one instance, even for @Singleton implementations. Correct, ATM we support only one hint per implementation.
? I think Marius needed that for some wysiwyg stuff and we actually support multiple hints per implementation. It's just gonna give you a new instance for each hint, which in my view is a bug, not a missing feature.
We don't support multiple hints per implementation. What we do is if we find multiple hints in the @Component annotation then we register several components. But you always have one component per role/hint. Using several hints in @Component is bad practice ATM. It means the code is serving different Roles and it's a better design to separate the concerns. Thanks -Vincent
Another approach is to deprecate the direct dependency declaration and instead introduce a factory that is responsible for selecting the default, but this breaks backwards compatibility. Not completely true. Imagine you have (Role, "default") as your current component and you wish to be able to choose various implementation from now on. What you could do is this:
* Write a new component, a Factory, that overrides the current component, i.e. by using the same (Role, "default"). This factory will then delegate to whatever other implementation it wishes.
That's only possible if the public API of the CM allows you to grab overriden components (non-default defaults :) )
From the user of (Role, "default")'s POV he won't see a single change.
The "I don't care, just give me the default" strategy works as long as the component implementation is self-contained and doesn't involve data communication. Let's take an example, PDF export.
Currently the PDF export is only possible via FOP. If we were to convert the current interface + implementation class into a proper component, we'd name it "default", since it's the only one and who needs a factory for only one implementation. Yes but we could also be thorough and instead implement a Provider<PDFExporter> instead.
People use it and they're happy because it just works. But we might soon add support for export via an office server. Suppose we want either FOP or Office to be usable as the default PDF export implementation. And suppose we'll want to keep both types of export active, so that we can use either one as the implementation for the default export of documents, the FOP implementation for exporting some kinds of documents like scientific articles, and the office connector for generating PDFs for presentations. Using the overrides mechanism we can only have one active at the same time, unless we introduce yet another factory which we can bypass using manual component lookup. Based on your use case you'll need a UI to ask the user what he wants to export, i.e. either a "scientific article" or a "presentation" and from his choice you'll pick the right implementation. You could also try to guess that dynamically by looking at what is being exported but that'll require a Factory to hold that logic.
I know what you mean though: for some reason you don't want that to be dynamic and you wish it to be static.
There's a problem with dynamicity though. Imagine an extension that wants to replace an implementation. With your proposal the best practice would be to introduce a new Hint since the "default" is chosen statically at configuration time. So that wouldn't work. After you install extensions you'd need to stop the wiki, change the binding to the new implementation from the extension and restart it. Of course you'd need to read the documentation of the extension to know you have to use it in replacement. Basically it would mean that extensions cannot override behaviors. They would just be able to add new components (like new Macros) but not modify behaviors at runtime.
But this only means we need to be able to change configuration without stopping the wiki and make it reload configs (might prove useful for other things as well), it doesn't mean we cannot do it "static".
If at some point we decide that the office implementation works better, we might consider changing the default implementation for the pdf component. This means that we'll change the hint of the FOP implementation from "default" to "fop", change the hint of the Office implementation from "office" to "default", and our new version of XE works great if people read the installation guide and properly configure the office connector. In practice we would have 2 choices with our current component impl.:
Choice 1: * Add 2 new implementations with hint1 and hint2 (hint1 being what was "default" before) * Keep the implementation with "default" hint but deprecate it and move it to legacy. Refactor it so that it delegates yo hint1 * Add a Provider to decide which impl to use based on whatever conditions we want
Choice 2: * Move "default" impl to "hint1" * Add "hint2" * Change "default" implementation to be a Composite that delegates to hint1 or hint2
But what about those that want to upgrade, but are happy with the older FOP implementation and don't want to add support for the office connector? Yes, in this case this is transparent for them (and it's a good thing in most caes!). This means they get autoupgrade to something better.
No, it means that for some reason we decided to change the underlying technology (e.g. change of licence), it doesn't mean that everybody is happy with the change.
They'll have to use patched versions of the two component implementations where their hints are reverted back to the old values. Easy? No. And even though "default" means "I don't care what the implementation does" It doesn't really mean this. We use "default" only when there's a single implementation. When there are more than 1 each one has a hint that is a qualifier to the implementation since there's no reason one is more default than the other.
, here it does matter a lot which implementation you're using. They have different requirements, and it's important to know if the implementation will require an office instance or not.
Saying that this won't happen since we're all really careful when designing our components is wishful thinking. We've refactored other more critical pieces of code than providing alternative implementations for a component, so we will find ourselves in situations where we'll have to switch from only one "default" implementation to several. I agree that we've refactored. And it has worked so far right? ;)
Designing our component manager to make it easy to transition is the right thing to do.
Still, my major problem is not about overrides, but about the semantics of "default" (or lack of it). This says nothing about the actual mechanisms behind the implementation, it just reflects the state of that particular component implementation: it's the default at the moment. Not caring what the implementation actually does works only when there is indeed just one possible implementation that is straight-forward. But in most cases, we do rely on another library that does the work for us, and libraries die, better alternatives come along, and changing that internal aspect of the implementation will sometimes be backwards incompatible, or have a different behavior. Sure, it does the same job, but it does it so differently that some will prefer to use the other approach. We have to let users decide which is their "default", and having multiple implementations with the "default" hint but different priorities is not very intuitive. Why not make everything default and remove hints completely if we don't really put any meaning into the hint?
This also means that we should only have components where there is a chance that another implementation might exist, because to the limit you can separate the interface from the implementation for any little piece of code that you write.
I sort of feel you for this default thing, but at the same time, it's also a matter of education of the developer, which needs to make sure that they put a technology hint to the component, besides the default hint. The pb is that, as long as there is only one implementation, regardless of the technology it's based on, you also need to put the default hint since otherwise you'll have to hardcode the reference to the technology everywhere if you wanna use that service. so in this case default would mean 'this is the one that should be used because there's no other, you dumb CM that is not capable of seeing that'.
This brings back some memories, but I don't know from what, about a system that was giving the available implementation regardless of its name. For example, we could make the CM return the only implementation, if only one exists, when asking for a component, regardless of its hint, so we don't have to put default everywhere. But then we need a strategy for the case when there are more.
And "default" adds another assumption: XWiki Enterprise is the ultimate target. Our defaults are the only ones that matter. As an example, all the *Configuration components have just one "default" implementation, which relies on xwiki.properties, XWiki.XWikiPreferences etc. Doesn't that tie the platform to the XWiki Enterprise wiki?
This not true in xwiki commons and rendering because I've made sure that we could use them outside of the XWiki Platform. They have default implementation that don't use XWiki Configuration module.
It's not a direct dependency visible at compilation time, it's worse, and invisible assumption about the final runtime. It's certainly not the default for other types of users that want to embed xwiki-commons or xwiki-platform components in a different type of end product. To me this isn't the default configuration, this is the default configuration used by XWiki Enterprise, thus my proposal of using something else as the generic component hint instead of "default". Ok thanks for the explanations. I understand better now what you mean.
Actually what you suggest could already be implemented using a best practice of always using Providers when you want a Component injected. In this manner by default you'll get the Generic Provider but anyone could implement a specific Provider implementation for it that would choose between various implementation based on whatever (a value in a META-INF/role-bindings.txt file, data from DB, etc).
<side note>Only issue with having Providers everywhere is that you get late verification of your system coherence since dependencies will be resolved only when they're used. OTOH this is a necessity in a fully-dynamic system ;)</side note>
Also, the notion of default doesn't always have a meaning. There are lots of cases when there are NO default. For example Macros or Transformations or…
Let's continue the discussion it's interesting :)
I'd like to review a bit the other Component system out there again to see what they do for this. It's important that they have support for this since we want to be able to switch to them one day. The 3 that I would review are: * Guice * CDI * OSGi
yes, we should learn from others. Maybe even use one?
Thanks, Anca
Thanks -Vincent
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
On 04/06/2012 12:36 PM, Vincent Massol wrote:
On Apr 6, 2012, at 11:43 AM, Anca Luca wrote:
I On 04/06/2012 09:35 AM, Vincent Massol wrote:
Hi Sergiu,
Note that below I'm going to play the devil's advocate since I think it's important we really think hard before changing anything and verify if our current implementation is not enough.
See below.
On Apr 5, 2012, at 8:44 PM, Sergiu Dumitriu wrote:
On 04/05/2012 12:51 PM, Anca Luca wrote:
On 04/05/2012 06:42 PM, Vincent Massol wrote:
Hi Sergiu,
On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
> Hi devs, > > Currently, requesting a component instance without a hint will look > for the implementation that uses the "default" hint, which makes it > difficult to change the implementation in an XWiki instance. Sure, it > is easy as long as all the implementations use the "default" hint, > but choosing the default between alternative implementations that > should all still be usable by themselves is not possible. > > Also, "default" is not really a good hint, since it describes the > state of the implementation, not the technology, the aspect that > makes it different from the others. It would be better to name each > implementation with a proper hint. > > I propose to define a mapping that can specify which hint is the > default for a component. In a text file, > META-INF/component-defaults.txt, we'll keep > componentinterface=defaulthint mappings. For example: > > com.xpn.xwiki.store.XWikiStoreInterface=hibernate > com.xpn.xwiki.store.migration.DataMigrationManager=hibernate > > And then, when we lookup the current storage implementation, we don't > need to check what is the configured hint in xwiki.cfg (or > xwiki.properties), we can just request the default implementation. > > If there's no mapping for a component, we'll continue to use the > "default" hint. > > I'm not sure where exactly to keep such files. We bundle a > components.txt file in each jar containing component implementations. > We could do the same for the components we consider the platform > defaults, and allow overrides in the > WEB-INF/classes/META-INF/component-defaults.txt file. Still, this > means that whenever platform defaults change, we need to keep another > special section in the release notes, to let users know about these > changes, so that they can manually revert to the old default if they > need to. > > In the future we could change existing components to give proper > hints instead of "default", where such a change is applicable. > > Another idea is to not use "default" at all, and instead go for a > generic "xwiki", "xe", "xwiki-platform" or something like that > whenever there's just one implementation for a component and we can't > find another hint to describe it. > > WDYT? This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one).
To decide which implementation is used you use a priority order, as described on: http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr...
I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it. "...choosing the default between alternative implementations that should all **still be usable by themselves** is not possible"
The overrides mechanism allows to change which component will be returned for the "default" hint, but all the others will be invisible.
One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki.
Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default. Exactly. For most of the "services" the XWiki platform currently has (storage, cache), we don't have a "default" implementation, but we rely on a kind of factory to lookup the configured default. That is an actual factory class in the case of the cache service, but just more code in the old XWiki.java class for the storage initialization. Yep that's how it works.
A standard way of selecting the default means that we'll need less factories, and less code is always a good thing. Yes but it has more limitation to what we have since with a proper Factory you can imagine all kind of logic to decide which implementation to use (hour of the day, whether the user is a premium user or not, etc).
BTW we do support Providers and the goal of the Provider is to be a factory for a given Role. So from now on, there should be no need to implement a Factory proper. Implementing a Provider is the new best practice for this.
Now, suppose one of the older components that had only one implementation, "default", gets alternative implementations, and we want to be able to allow more than one to be active in a wiki, and let the administrator decide which one should be considered the default. How can we approach this? The only way is indeed to have multiple hints, but last time I checked this resulted in more than one instance, even for @Singleton implementations. Correct, ATM we support only one hint per implementation. ? I think Marius needed that for some wysiwyg stuff and we actually support multiple hints per implementation. It's just gonna give you a new instance for each hint, which in my view is a bug, not a missing feature. We don't support multiple hints per implementation. What we do is if we find multiple hints in the @Component annotation then we register several components. But you always have one component per role/hint.
Using several hints in @Component is bad practice ATM.
But then what Sergiu said when he launched this mail is even worse. Already you're forced to put default because otherwise your code cannot be used without dragging a reference to the implementation itself, and then you cannot put anything related to the actual implementation that would describe why is that impl specific because it's a bad practice to put 2. E.g. I have a diff service for the annotations, which produces differences based on characters as a unit of modification (you could also have word or line). The code that uses this would work fine, independently of the strategy that's used to compute diffs. This diff service right now has "characters, default" as hints. If this is a bad practice, then I need to leave only default as the hint, since if I would put "characters" then all the code that requires this service will have to specify that they need a characters based service, which is not true. Or yes, I could, of course, write a factory with the hint default that serves the characters based one, because that's the only available, but in my view, if we make that all the time when there's only one implementation available, it's a bit too much.
It means the code is serving different Roles
hints you mean
and it's a better design to separate the concerns.
The problem is the "default" is not a concern ;), "default" is "there is no other available anyway". Thanks, Anca
Thanks -Vincent
Another approach is to deprecate the direct dependency declaration and instead introduce a factory that is responsible for selecting the default, but this breaks backwards compatibility. Not completely true. Imagine you have (Role, "default") as your current component and you wish to be able to choose various implementation from now on. What you could do is this:
* Write a new component, a Factory, that overrides the current component, i.e. by using the same (Role, "default"). This factory will then delegate to whatever other implementation it wishes. That's only possible if the public API of the CM allows you to grab overriden components (non-default defaults :) )
From the user of (Role, "default")'s POV he won't see a single change.
The "I don't care, just give me the default" strategy works as long as the component implementation is self-contained and doesn't involve data communication. Let's take an example, PDF export.
Currently the PDF export is only possible via FOP. If we were to convert the current interface + implementation class into a proper component, we'd name it "default", since it's the only one and who needs a factory for only one implementation. Yes but we could also be thorough and instead implement a Provider<PDFExporter> instead.
People use it and they're happy because it just works. But we might soon add support for export via an office server. Suppose we want either FOP or Office to be usable as the default PDF export implementation. And suppose we'll want to keep both types of export active, so that we can use either one as the implementation for the default export of documents, the FOP implementation for exporting some kinds of documents like scientific articles, and the office connector for generating PDFs for presentations. Using the overrides mechanism we can only have one active at the same time, unless we introduce yet another factory which we can bypass using manual component lookup. Based on your use case you'll need a UI to ask the user what he wants to export, i.e. either a "scientific article" or a "presentation" and from his choice you'll pick the right implementation. You could also try to guess that dynamically by looking at what is being exported but that'll require a Factory to hold that logic.
I know what you mean though: for some reason you don't want that to be dynamic and you wish it to be static.
There's a problem with dynamicity though. Imagine an extension that wants to replace an implementation. With your proposal the best practice would be to introduce a new Hint since the "default" is chosen statically at configuration time. So that wouldn't work. After you install extensions you'd need to stop the wiki, change the binding to the new implementation from the extension and restart it. Of course you'd need to read the documentation of the extension to know you have to use it in replacement. Basically it would mean that extensions cannot override behaviors. They would just be able to add new components (like new Macros) but not modify behaviors at runtime. But this only means we need to be able to change configuration without stopping the wiki and make it reload configs (might prove useful for other things as well), it doesn't mean we cannot do it "static".
If at some point we decide that the office implementation works better, we might consider changing the default implementation for the pdf component. This means that we'll change the hint of the FOP implementation from "default" to "fop", change the hint of the Office implementation from "office" to "default", and our new version of XE works great if people read the installation guide and properly configure the office connector. In practice we would have 2 choices with our current component impl.:
Choice 1: * Add 2 new implementations with hint1 and hint2 (hint1 being what was "default" before) * Keep the implementation with "default" hint but deprecate it and move it to legacy. Refactor it so that it delegates yo hint1 * Add a Provider to decide which impl to use based on whatever conditions we want
Choice 2: * Move "default" impl to "hint1" * Add "hint2" * Change "default" implementation to be a Composite that delegates to hint1 or hint2
But what about those that want to upgrade, but are happy with the older FOP implementation and don't want to add support for the office connector? Yes, in this case this is transparent for them (and it's a good thing in most caes!). This means they get autoupgrade to something better. No, it means that for some reason we decided to change the underlying technology (e.g. change of licence), it doesn't mean that everybody is happy with the change. They'll have to use patched versions of the two component implementations where their hints are reverted back to the old values. Easy? No. And even though "default" means "I don't care what the implementation does" It doesn't really mean this. We use "default" only when there's a single implementation. When there are more than 1 each one has a hint that is a qualifier to the implementation since there's no reason one is more default than the other.
, here it does matter a lot which implementation you're using. They have different requirements, and it's important to know if the implementation will require an office instance or not.
Saying that this won't happen since we're all really careful when designing our components is wishful thinking. We've refactored other more critical pieces of code than providing alternative implementations for a component, so we will find ourselves in situations where we'll have to switch from only one "default" implementation to several. I agree that we've refactored. And it has worked so far right? ;)
Designing our component manager to make it easy to transition is the right thing to do.
Still, my major problem is not about overrides, but about the semantics of "default" (or lack of it). This says nothing about the actual mechanisms behind the implementation, it just reflects the state of that particular component implementation: it's the default at the moment. Not caring what the implementation actually does works only when there is indeed just one possible implementation that is straight-forward. But in most cases, we do rely on another library that does the work for us, and libraries die, better alternatives come along, and changing that internal aspect of the implementation will sometimes be backwards incompatible, or have a different behavior. Sure, it does the same job, but it does it so differently that some will prefer to use the other approach. We have to let users decide which is their "default", and having multiple implementations with the "default" hint but different priorities is not very intuitive. Why not make everything default and remove hints completely if we don't really put any meaning into the hint? This also means that we should only have components where there is a chance that another implementation might exist, because to the limit you can separate the interface from the implementation for any little piece of code that you write.
I sort of feel you for this default thing, but at the same time, it's also a matter of education of the developer, which needs to make sure that they put a technology hint to the component, besides the default hint. The pb is that, as long as there is only one implementation, regardless of the technology it's based on, you also need to put the default hint since otherwise you'll have to hardcode the reference to the technology everywhere if you wanna use that service. so in this case default would mean 'this is the one that should be used because there's no other, you dumb CM that is not capable of seeing that'.
This brings back some memories, but I don't know from what, about a system that was giving the available implementation regardless of its name. For example, we could make the CM return the only implementation, if only one exists, when asking for a component, regardless of its hint, so we don't have to put default everywhere. But then we need a strategy for the case when there are more.
And "default" adds another assumption: XWiki Enterprise is the ultimate target. Our defaults are the only ones that matter. As an example, all the *Configuration components have just one "default" implementation, which relies on xwiki.properties, XWiki.XWikiPreferences etc. Doesn't that tie the platform to the XWiki Enterprise wiki? This not true in xwiki commons and rendering because I've made sure that we could use them outside of the XWiki Platform. They have default implementation that don't use XWiki Configuration module.
It's not a direct dependency visible at compilation time, it's worse, and invisible assumption about the final runtime. It's certainly not the default for other types of users that want to embed xwiki-commons or xwiki-platform components in a different type of end product. To me this isn't the default configuration, this is the default configuration used by XWiki Enterprise, thus my proposal of using something else as the generic component hint instead of "default". Ok thanks for the explanations. I understand better now what you mean.
Actually what you suggest could already be implemented using a best practice of always using Providers when you want a Component injected. In this manner by default you'll get the Generic Provider but anyone could implement a specific Provider implementation for it that would choose between various implementation based on whatever (a value in a META-INF/role-bindings.txt file, data from DB, etc).
<side note>Only issue with having Providers everywhere is that you get late verification of your system coherence since dependencies will be resolved only when they're used. OTOH this is a necessity in a fully-dynamic system ;)</side note>
Also, the notion of default doesn't always have a meaning. There are lots of cases when there are NO default. For example Macros or Transformations or…
Let's continue the discussion it's interesting :)
I'd like to review a bit the other Component system out there again to see what they do for this. It's important that they have support for this since we want to be able to switch to them one day. The 3 that I would review are: * Guice * CDI * OSGi yes, we should learn from others. Maybe even use one?
Thanks, Anca
Thanks -Vincent
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
On Apr 5, 2012, at 6:51 PM, Anca Luca wrote:
On 04/05/2012 06:42 PM, Vincent Massol wrote:
Hi Sergiu,
On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
WDYT? This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one).
To decide which implementation is used you use a priority order, as described on: http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr...
I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it.
One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki.
This is supported already.
Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default.
Yes that's because the hint is not a configuration param. It's an intrinsic information about what it represents. When you have: @Named("ldap") public class DefaultLDAPAuthenticator implements Authenticator ... It means that (Authenticator,"ldap") means the LDAP Authenticator implementation and not something else. If you want to change that implementation you need to write a component with (Authenticator,"ldap"). Now if what you want is way to have *several* implementations of the same Role at once in the classloader you need to use different hints and if what you want is pick one implementation from those various implementation and make it your default you need to configure somewhere which one to use. We use that everywhere in the XE. 2 examples: * Macros. In this case it's the user who says which ones to use by using the "hint" as the macro name telling XWiki which macro implementation to use: {{hint .../}} * Storage implementation. In this case we want only one default storage impl to be used. What we do is have a Storage Manager which is in charge of deciding which implementation to use. In this case the selection is based on a configuration param which contains the hint of the implementation to use (for ex: xwiki.store.main.hint=hibernate). I don't see the limitation. It's even more powerful than what you suggest (which is static rewiring of component implementations) since in this case we support dynamic rewiring based on any rule. I still fail to see the use case that would make what you suggest required. Thanks -Vincent
On Fri, Apr 6, 2012 at 8:51 AM, Vincent Massol <[email protected]> wrote:
On Apr 5, 2012, at 6:51 PM, Anca Luca wrote:
On 04/05/2012 06:42 PM, Vincent Massol wrote:
Hi Sergiu,
On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
WDYT? This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one).
To decide which implementation is used you use a priority order, as described on: http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr...
I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it.
One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki.
This is supported already.
Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default.
Yes that's because the hint is not a configuration param. It's an intrinsic information about what it represents. When you have:
@Named("ldap") public class DefaultLDAPAuthenticator implements Authenticator ...
It means that (Authenticator,"ldap") means the LDAP Authenticator implementation and not something else. If you want to change that implementation you need to write a component with (Authenticator,"ldap").
Now if what you want is way to have *several* implementations of the same Role at once in the classloader you need to use different hints and if what you want is pick one implementation from those various implementation and make it your default you need to configure somewhere which one to use. We use that everywhere in the XE.
2 examples: * Macros. In this case it's the user who says which ones to use by using the "hint" as the macro name telling XWiki which macro implementation to use: {{hint .../}} * Storage implementation. In this case we want only one default storage impl to be used. What we do is have a Storage Manager which is in charge of deciding which implementation to use. In this case the selection is based on a configuration param which contains the hint of the implementation to use (for ex: xwiki.store.main.hint=hibernate).
I don't see the limitation. It's even more powerful than what you suggest (which is static rewiring of component implementations) since in this case we support dynamic rewiring based on any rule.
I still fail to see the use case that would make what you suggest required.
From what I understood it's not that much about adding something we can't do right now but Sergiu basically wants to make Storage Manager useless by introducing a generic system working for any set of components with the same use case of configurable default implementation (cache factory, storage, etc.). Instead of going through a manager you would directly lookup/inject the "default" implementation which would not be the component with role MyRole and hint "default" but the configured default component (can be true for any rolehint, like changing which macro implementation to use for the hint "velocity" for example choosing between XWiki and JSR223 implementation).
Right Sergiu ?
Thanks -Vincent _______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
-- Thomas Mortagne
On 04/06/2012 08:51 AM, Vincent Massol wrote:
On Apr 5, 2012, at 6:51 PM, Anca Luca wrote:
On 04/05/2012 06:42 PM, Vincent Massol wrote:
Hi Sergiu,
On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
WDYT? This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one).
To decide which implementation is used you use a priority order, as described on: http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr...
I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it. One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki. This is supported already.
Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default. Yes that's because the hint is not a configuration param. It's an intrinsic information about what it represents. When you have:
@Named("ldap") public class DefaultLDAPAuthenticator implements Authenticator ...
It means that (Authenticator,"ldap") means the LDAP Authenticator implementation and not something else. If you want to change that implementation you need to write a component with (Authenticator,"ldap").
Now if what you want is way to have *several* implementations of the same Role at once in the classloader you need to use different hints and if what you want is pick one implementation from those various implementation and make it your default you need to configure somewhere which one to use. We use that everywhere in the XE.
2 examples: * Macros. In this case it's the user who says which ones to use by using the "hint" as the macro name telling XWiki which macro implementation to use: {{hint .../}} * Storage implementation. In this case we want only one default storage impl to be used. What we do is have a Storage Manager which is in charge of deciding which implementation to use. In this case the selection is based on a configuration param which contains the hint of the implementation to use (for ex: xwiki.store.main.hint=hibernate).
I don't see the limitation. It's even more powerful than what you suggest (which is static rewiring of component implementations) since in this case we support dynamic rewiring based on any rule.
I still fail to see the use case that would make what you suggest required.
Ok, so you write a factory (call it manager if you want, I can also call it proxy if I want) that has the hint default and that actually does nothing but give you the implementation that was configured at default with one or the others of the means. So if you want the user to have a choice (the dude installing xwiki and having it running), you must _always_ write these factories, as soon as there is more than one implementation, and have it read configuration from some place. If somebody builds something based on xwiki platform and adds an extra implementation and wants to be able to change that, he needs to write his new implementation + this factory (+ a bit of magic to actually overcome the fact that the old implementation was "default" and now his new implementation must be default but also needs to be able to dispatch to the old default -- here I so much agree with sergiu default shouldn't exist). In addition, most of these factories will work exactly the same: they will look for a param in the configuration file and use that hint as the default. Of course we can provide an AbstractXWikiConfigurationBasedGenericComponentImplementationManager to make it easy for people to write their own. It is covering the use case, but it's a pain. In addition, it really depends on the fact that the person that wrote the multiple implementations thought of whether there should be something that dispatches between them or not (because somebody at some point might wanna change it). Since all these managers will be the same, why not add an "implicit implementation" of this in the CM, by just allowing a hint to be configured in the config file, and the CM would read it on the fly? This doesn't mean that you cannot write your own if you want, that dispatches based on the moon phase, for example. Note that I push more towards dumb-simple things, although I understand why it's a complex topic. Thanks, Anca
Thanks -Vincent _______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs
Hi Anca, On Apr 6, 2012, at 10:58 AM, Anca Luca wrote:
On 04/06/2012 08:51 AM, Vincent Massol wrote:
On Apr 5, 2012, at 6:51 PM, Anca Luca wrote:
On 04/05/2012 06:42 PM, Vincent Massol wrote:
Hi Sergiu,
On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
WDYT? This is not really how it's been designed ATM. Whenever you wish to use a different implementation of a component you use a component implementation with the same role and same hint. You then make it available in your classpath. (Of course you can also do this at runtime simply by registering a new implementation over the old one).
To decide which implementation is used you use a priority order, as described on: http://extensions.xwiki.org/xwiki/bin/view/Extension/Component+Module#HOverr...
I'd be curious to know your exact use case and understand why the current mechanism doesn't work for it. One usecase I see is that you have multiple implementations and you want to change the default one for a specific running instance of xwiki. This is supported already.
Overwrite mechanism only allows you to say which impl should be used from the _components with the same hint_. However, you cannot change the hint of a component at configuration time, so if you have a standard distr of xwiki and you want to use ldap authentication, let's say (if only auth was impl with components), unless you do some java to add the default hint to the ldap implementation and then to specify that this one has priority over all the default ones, I don't see how you can re-wire the default. Yes that's because the hint is not a configuration param. It's an intrinsic information about what it represents. When you have:
@Named("ldap") public class DefaultLDAPAuthenticator implements Authenticator ...
It means that (Authenticator,"ldap") means the LDAP Authenticator implementation and not something else. If you want to change that implementation you need to write a component with (Authenticator,"ldap").
Now if what you want is way to have *several* implementations of the same Role at once in the classloader you need to use different hints and if what you want is pick one implementation from those various implementation and make it your default you need to configure somewhere which one to use. We use that everywhere in the XE.
2 examples: * Macros. In this case it's the user who says which ones to use by using the "hint" as the macro name telling XWiki which macro implementation to use: {{hint .../}} * Storage implementation. In this case we want only one default storage impl to be used. What we do is have a Storage Manager which is in charge of deciding which implementation to use. In this case the selection is based on a configuration param which contains the hint of the implementation to use (for ex: xwiki.store.main.hint=hibernate).
I don't see the limitation. It's even more powerful than what you suggest (which is static rewiring of component implementations) since in this case we support dynamic rewiring based on any rule.
I still fail to see the use case that would make what you suggest required.
Ok, so you write a factory (call it manager if you want, I can also call it proxy if I want) that has the hint default and that actually does nothing but give you the implementation that was configured at default with one or the others of the means. So if you want the user to have a choice (the dude installing xwiki and having it running), you must _always_ write these factories, as soon as there is more than one implementation, and have it read configuration from some place. If somebody builds something based on xwiki platform and adds an extra implementation and wants to be able to change that, he needs to write his new implementation + this factory (+ a bit of magic to actually overcome the fact that the old implementation was "default" and now his new implementation must be default but also needs to be able to dispatch to the old default -- here I so much agree with sergiu default shouldn't exist).
In addition, most of these factories will work exactly the same: they will look for a param in the configuration file and use that hint as the default. Of course we can provide an AbstractXWikiConfigurationBasedGenericComponentImplementationManager to make it easy for people to write their own.
It is covering the use case, but it's a pain. In addition, it really depends on the fact that the person that wrote the multiple implementations thought of whether there should be something that dispatches between them or not (because somebody at some point might wanna change it).
Since all these managers will be the same, why not add an "implicit implementation" of this in the CM, by just allowing a hint to be configured in the config file, and the CM would read it on the fly?
This doesn't mean that you cannot write your own if you want, that dispatches based on the moon phase, for example.
Note that I push more towards dumb-simple things, although I understand why it's a complex topic.
Sorry, I replied to your mail first and then I saw and replied to Sergiu's. I have provided more details in the that second mail. Thanks -Vincent
Actually, another way of presenting your proposal in a more generic way would be: "Add support for component Aliases". It's slightly more generic since it's not just about default. If you wish to change a hint for another one because it's not well named you could do it through an alias. This would also mean adding a ComponentManager.setAlias(String alias, Type existingRole, String existingHint). Anyway, the next step IMO is to check what Guice/CDI and OSGi are doing in this regards. Thanks -Vincent On Apr 5, 2012, at 5:55 PM, Sergiu Dumitriu wrote:
Hi devs,
Currently, requesting a component instance without a hint will look for the implementation that uses the "default" hint, which makes it difficult to change the implementation in an XWiki instance. Sure, it is easy as long as all the implementations use the "default" hint, but choosing the default between alternative implementations that should all still be usable by themselves is not possible.
Also, "default" is not really a good hint, since it describes the state of the implementation, not the technology, the aspect that makes it different from the others. It would be better to name each implementation with a proper hint.
I propose to define a mapping that can specify which hint is the default for a component. In a text file, META-INF/component-defaults.txt, we'll keep componentinterface=defaulthint mappings. For example:
com.xpn.xwiki.store.XWikiStoreInterface=hibernate com.xpn.xwiki.store.migration.DataMigrationManager=hibernate
And then, when we lookup the current storage implementation, we don't need to check what is the configured hint in xwiki.cfg (or xwiki.properties), we can just request the default implementation.
If there's no mapping for a component, we'll continue to use the "default" hint.
I'm not sure where exactly to keep such files. We bundle a components.txt file in each jar containing component implementations. We could do the same for the components we consider the platform defaults, and allow overrides in the WEB-INF/classes/META-INF/component-defaults.txt file. Still, this means that whenever platform defaults change, we need to keep another special section in the release notes, to let users know about these changes, so that they can manually revert to the old default if they need to.
In the future we could change existing components to give proper hints instead of "default", where such a change is applicable.
Another idea is to not use "default" at all, and instead go for a generic "xwiki", "xe", "xwiki-platform" or something like that whenever there's just one implementation for a component and we can't find another hint to describe it.
WDYT? -- Sergiu Dumitriu
participants (5)
-
Anca Luca -
Marius Dumitru Florea -
Sergiu Dumitriu -
Thomas Mortagne -
Vincent Massol