Hi, (another lengthy e-mail, if we're lucky, the last one..)
took a look at how could we achieve backward compatibility for (1)plugins, (2)filters and (3)page providers, while developing the public API. After that I'd like two make two brief comments about (4)next steps and (5)having JSPWiki installations' "islands" (1) Plugins plugins execution is located on DefaultPluginManager and, roughly, looks like this: try { return plugin.execute( context, params ); // plugin is a WikiPlugin, context is a WikiContext } catch( final PluginException e ) { [...] throw ( PluginException )e.fillInStackTrace(); } catch( final Throwable t ) { [...] throw new PluginException( rb.getString( "plugin.error.failed" ), t ); } If the suggested change for the public plugin api signature (context becoming Context instead of WikiContext), a plugin coded against "old" (2.11.0.M6 and below) will raise an AbstractMethodError here. However, we can bypass that and achieve plugin execution by changing the above code to: try { try { return plugin.execute( context, params ); } catch( final AbstractMethodError ame ) { log.warn( classname + "uses WikiContext instead of Context in its execute method"); log.warn( "Please contact the plugin's author so there can be a new release of the plugin " + "implementing the method signature" ); return ( String )plugin.getClass() // this returns the concrete type implementing the WikiPlugin interface .getMethod( "execute", Class.forName( "org.apache.wiki.WikiContext" ), Map.class ) .invoke( plugin, context, params ); } } catch( final PluginException e ) { [...] throw ( PluginException )e.fillInStackTrace(); } catch( final Throwable t ) { [...] throw new PluginException( rb.getString( "plugin.error.failed" ), t ); } WikiContext#getEngine() method could also be changed so its signature, instead of returning an Engine, returns a WikiEngine. That should allow reaching methods from WikiEngine not present in Engine, like, f.ex, all the getXYZManager() methods. However, note that there are some methods in WikiEngine that are not longer there, they've been moved to places were they made sense. These methods were used mainly for JSPWiki internal operations, so they're unlikely used in custom plugins. It's not impossible, though, but this kind of change should be expected on a minor release (the ones changing the middle number, i.e., 2.10.6 to 2.11.0). Another way to solve this, which would avoid the use of reflection is turning WikiPlugin into an adapter. Let's say a new interface org.apache.wiki.api.plugin.Plugin is created next to WikiPlugin, which contains the proposed public api change: public interface Plugin { String CORE_PLUGINS_RESOURCEBUNDLE = "plugin.PluginResources"; String execute( Context context, Map< String, String > params ) throws PluginException; } then WikiPlugin could become an adapter: public interface WikiPlugin extends Plugin { /** {@inheritDoc} */ @Override default String execute( final Context context, final Map< String, String > params ) throws PluginException { Logger.getLogger( WikiPlugin.class ).warn( this.getClass().getName() + " implements deprecated org.apache.wiki.api.plugin.WikiPlugin" ); Logger.getLogger( WikiPlugin.class ).warn( "Please contact the plugin's author so there can be a new release of the plugin " + "implementing the new org.apache.wiki.api.plugin.Plugin interface" ); return execute( ( WikiContext )context, params ); } String execute( WikiContext context, Map< String, String > params ) throws PluginException; } WikiPlugin, although being in the api.plugin package would NOT be part of the public api, i.e., it would remain on the jspwiki-main module, whereas the public api would be in a new jspwiki-api maven module. I'm more inclined to this, mostly because all interfaces/classes on the public api are not prefixed with "Wiki" except for WikiPlugin, and then all the public api would be uniformly named. That would please all people like me who are somewhere in-between software engineers and people with obsessive-compulsive disorder :-) Jokes aside, the important thing is that current plugins would still run with the new API. (And WikiPlugin would eventually be deleted from the source code) Why introduce then the first option? Because that would be the way to go with (2) Filters Not surpringsily, filter execution is handled by the different methods on DefaultFilterManager. By catching different AbstractMethodError on those methods we can make "old" filters work alongside the new API. (3) Page Providers This one is trickier as WikiPageProvider and WikiAttachmentProvider have methods like: Collection< SearchResult > findPages( QueryItem[] query ); with SearchResult and QueryItem being in the search package, with both of them to land on the public api, thus changing their package. Happens the same with at least Acls, Page/WikiPage Attachment/WikiAttachment. What I've thought in this case to make them usable with the new API is a couple of WikiPage210AdapterProvider / WikiAttachment210AdapterProvider which would wrap the 3rd party implementation (that should be located through a property on the jspwiki[-custom].properties file). SearchResult / QueryItem classes would not be moved to the API package, but copied. The API ones should be used throughout the code, but the original ones (SearchResult / QueryItem from search package) would be kept so that the adapter providers can transform back and forth from the adapter provider to 3rd party provider. Also, the calls to the 3rd party provider would be made using the same reflection technique as before. (4) Next steps Hopefully, no more kilometric e-mails. On the short term, I'm planning to extract the event package to its own jspwiki-event maven module, and create a jspwiki-api maven module. This module would contain the full public API, although right now only part of it would be used (Engine, Session and maybe a few more classes), so it can be discussed and reasoned around with a more clear focus. After that, re-introduce API compatibility with plugins (easy) and filters (a bit more of work but hopefully doable too without spending too much time on it). It would be really, *really* nice if someone volunteered for the page providers: keeping the existing extensions is gone to take some time that I was planning to spend on other tasks, so any help with that would mean more time spent on the public api. (5) JSPWiki installations' islands We don't want to have them, and we strive to avoid them as much as possible. Said that, I think they're bound to happen someday. Keeping the backward compatibility is an ongoing burden. It is not that we shouldn't have it as a top priority, but that doesn't mean is the absolute driver. JSPWiki API hasn't changed in ~7 years. A minor release after introducing the public API (that is on 2.12.0 or 3.1.0, whatever we see fit) I plan / like to remove the backward compatibility introduced above, as it also means more complexity on the code base. That would be a breaking change in the API in about 8-9 years, which I don't find completely unreasonable. thoughts? best regards, juan pablo On Sat, Mar 7, 2020 at 11:25 PM Juan Pablo Santos Rodríguez < juanpablo.san...@gmail.com> wrote: > Hi Murray, > > I'll look into make the current plugins mantain their signature if > possible. As I wrote else-thread, keep in mind the 6 last > releases contain code changes that could result in custom plugins / > filters not working anymore. That would also > happen on this release, whether the plugin signature changes or not. What > I wouldn't want to do is to include back > code that would make [#1] back into [#2].. > > > best regards, > juan pablo > > [#1]: > https://jspwiki-wiki.apache.org/attach/JSPWiki3APIDesignProposal/highwheel-master.png > [#2]: > https://jspwiki-wiki.apache.org/attach/JSPWiki3APIDesignProposal/highwheel-2.11.0.M6-reduced.png > (original > image resulted in 36MB, have to scale it to keep the size reasonable, to > see the full details is better to execute > the maven plugin..) > > On Sat, Mar 7, 2020 at 4:21 AM Murray Altheim <murra...@altheim.com> > wrote: > >> >> > Hi Murray, >> > >> > for plugins, most probably there'll be a signature change on WikiPlugin, >> > from: >> > String execute( WikiContext context, Map< String, String > params ) >> throws >> > PluginException; >> > >> > to: >> > String execute( Context context, Map< String, String > params ) throws >> > PluginException; >> >> Hi Juan Pablo, >> >> I realise you can't promise anything, but what I'm asking is that there >> be an adapter-pattern package that maintains **exactly** the same >> signature as the existing plugins, if at all possible. If we require >> people >> to re-code and ecompile plugins then in many cases they simply won't >> upgrade JSPWiki, as in many cases they won't have time, don't have >> the developer time or experience or personnel available, etc. as I >> mentioned previously. >> >> If the changes proposed as part of this public API are merely changes >> of name and package location (effectively facades over the existing >> code), then an adapter package should be possible. If not, I can't say >> I'd advocate for making such a change as I believe it would segregate >> existing users into two camps: those able to re-code and re-install an >> update, and those who can't due to existing plugins. That seems an >> overly high price for the existence of a new public API that doesn't >> add functionality, i.e., if we don't provide a compatible bridging adapter >> package. >> >> Cheers, >> >> Murray >> >> >> ........................................................................... >> Murray Altheim <murray18 at altheim dot com> = = >> === >> http://www.altheim.com/murray/ === >> === >> = = >> === >> In the evening >> The rice leaves in the garden >> Rustle in the autumn wind >> That blows through my reed hut. >> -- Minamoto no Tsunenobu >> >> >> >>