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#HOver…
>
>
> 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/