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#HOverrides >>>>>>>> >>>>>>>> >>>>>>>> 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/xwiki-platform-wysiwyg/xwiki-platform-wysiwyg-server/src/main/java/org/xwiki/wysiwyg/server/internal/filter/http/MutableHttpServletRequestFactory.java >>> >>> 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 _______________________________________________ devs mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/devs

