Another idea that I had while looking through CDI is supporting a unit of work logging feature LOG4J2-1630 [1] might be supportable with something similar to @ConversationScoped in CDI [2].
[1]: https://issues.apache.org/jira/browse/LOG4J2-1630 [2]: https://docs.jboss.org/cdi/api/2.0/javax/enterprise/context/ConversationScoped.html On Sat, 9 Nov 2019 at 11:46, Matt Sicker <boa...@gmail.com> wrote: > > ScriptRef is a fairly simple conversion: you'd either add @Inject on > its current constructor (we'd make ScriptManager a singleton or > similar scope) and potentially adding a configuration scope annotation > on the name parameter (the default scope in javax.inject is supposed > to be effectively a prototype scope), or you'd change the > Configuration parameter in the factory method to be ScriptManager > instead. No scope annotation would likely be required because there > would only be a single ScriptManager to choose from the available > scopes. > > CronTriggeringPolicy could be likewise update the same way. This would > be even easier to support by adding a TypeConverter for > CronExpression. > > ScriptPatternSelector is slightly more interesting. The StrSubstitutor > can be injected directly (probably a configuration-scope object). I'm > not currently sure how to model the configuration properties since > it's just a string->string map currently, though we could always add a > wrapper class there if necessary. > > For AbstractLayout, the configuration can be replaced by the injected > StrSubstitutor as well. AbstractStringLayout relies on the root logger > config, and this is one of those scenarios where I expect the > injection API to really show off features. This would be a > LoggerConfig injection with some sort of qualifier. > > As for Lookup overhead, I don't imagine this system to introduce much > overhead (if any at all once JIT'd) since constructors and such are > assembled at startup to an extent. The static code generation version > should further avoid overhead as it would just be directly setting up > objects without reflection. > > On Tue, 5 Nov 2019 at 11:25, Matt Sicker <boa...@gmail.com> wrote: > > > > Yes, these sound like great starting points. I'll work on a proof of > > concept of what I imagine the classes can look like after implementing > > the new injection system. > > > > On Mon, 4 Nov 2019 at 22:48, Ralph Goers <ralph.go...@dslextreme.com> wrote: > > > > > > PatternLayout and RFC5424Layout use the Configuration to pass to > > > Converters, primarily so they can use the Interpolator. > > > CronTriggeringPolicy and IdlePurgePolicy access the Configuration to get > > > to the ConfigurationScheduler. ScriptPatternSelector, and all other > > > Script plugins, accesses the Configuration to ge to the ScriptManager. > > > > > > Note that Lookups all have no-arg constructors but some of them, such as > > > Log4jLookup, need access to the Configuration. They do that by extending > > > AbstractConfigurationAwareLookup. That could obviously be replaced with > > > an annotation to perform the injection, although checking for the > > > interface probably involves less overhead. > > > > > > Hopefully this is what you are looking for. I am sure there are other > > > cases though. > > > > > > Ralph > > > > > > > > > > > > > On Nov 4, 2019, at 1:18 PM, Matt Sicker <boa...@gmail.com> wrote: > > > > > > > > Do you have any example plugins that might be a good example to showcase > > > > the scopes and qualifiers model? Preferably a plugin that injects a > > > > Configuration in order to obtain some other services or other ad hoc > > > > type > > > > plugins. Any plugin using just attributes (and elements and values) > > > > would > > > > be trivial to convert to the updated system (they’d likely be unchanged > > > > depending on how I model stereotypes; this is one area I intend to > > > > significantly diverge from CDI and act more like Spring where you can > > > > make > > > > stereotypes out of almost any annotation instead of just qualifiers and > > > > a > > > > single scope), so a plugin that needs injected values from elsewhere > > > > would > > > > probably showcase this idea best. > > > > > > > > On Sun, Nov 3, 2019 at 23:30 Matt Sicker <boa...@gmail.com> wrote: > > > > > > > >> I see what you did with the annotation processor. I figured I’d be > > > >> able to > > > >> add more metadata in the service class generated basically. If we can > > > >> identify the various logical scopes in the library, I think that could > > > >> lead > > > >> to less potential bugs. > > > >> > > > >> On Sun, Nov 3, 2019 at 14:14 Ralph Goers <ralph.go...@dslextreme.com> > > > >> wrote: > > > >> > > > >>> I have a couple of comments: > > > >>> It isn’t really possible for me to know what you are suggesting > > > >>> without > > > >>> seeing some examples of how plugins would be defined. > > > >>> I have a suspicion the scopes could get nasty. Some plugins would be > > > >>> tied > > > >>> to the LoggerContext, which essentially has a lifetime of the > > > >>> ClassLoader > > > >>> (or Bundle, or Module), while others are tied to the configuration so > > > >>> have > > > >>> that lifetime. I am afraid of the problems that would be introduced > > > >>> if a > > > >>> Plugin tied to the LoggerContext suddenly has a configuration scope. > > > >>> That > > > >>> would mean having to worry about thread safety in places we currently > > > >>> may > > > >>> not have to. But again, I would want to see examples to be sure. > > > >>> Using the annotation processor in 3.0 is currently required when using > > > >>> OSGi or JPMS. This is because OSGi requires bundle loading and JPMS > > > >>> requires the use of the ServiceLoader. We do not want to have to load > > > >>> each > > > >>> and every plugin via the ServiceLoader so instead the PluginService > > > >>> class > > > >>> is loaded, which contains a Map of all the plugins in the > > > >>> bundle/module. I > > > >>> don’t see how you can avoid this. That said, you are certainly free > > > >>> to > > > >>> make the PluginService smarter and more efficient. > > > >>> > > > >>> Ralph > > > >>> > > > >>>> On Nov 3, 2019, at 12:18 PM, Matt Sicker <boa...@gmail.com> wrote: > > > >>>> > > > >>>> Oh, almost forgot to mention my other main goal here: I have a > > > >>>> hypothesis that if designed our APIs with inversion of control in > > > >>>> mind, programmatic configuration and extension should be _much_ > > > >>>> easier > > > >>>> to support while maintaining backward compatibility, too. While the > > > >>>> configuration framework itself is extremely powerful for creating > > > >>>> fairly dynamic configurations, a non-trivial amount of users want > > > >>>> more > > > >>>> programmatic control than any of the APIs we support. > > > >>>> > > > >>>> On Sat, 2 Nov 2019 at 16:04, Matt Sicker <boa...@gmail.com> wrote: > > > >>>>> > > > >>>>> I've been working on this part time over the weekends lately, and > > > >>>>> after exploring a bit of Guice and CDI, I've come to the conclusion > > > >>>>> that if we were to rebase the plugin system on any annotation style, > > > >>>>> it seems as though CDI provides a fairly good set of extensions to > > > >>>>> javax.inject which would potentially work well with our existing > > > >>>>> annotations for backward compatibility. I wouldn't want to introduce > > > >>>>> an actual dependency on it, but a plugin SPI inspired by it could > > > >>>>> potentially work. A nice advantage to adopting a CDI-like system is > > > >>>>> that it should be simpler to use by other developers who aren't > > > >>>>> familiar with our custom framework. > > > >>>>> > > > >>>>> General overview of potential changes: > > > >>>>> > > > >>>>> * In addition to scopes and qualifiers, introduce stereotype > > > >>>>> annotations which are used for combining multiple annotations. This > > > >>>>> will help a lot in making old annotations still work properly. > > > >>>>> * Introduce a Produces and Disposes annotation that work similarly > > > >>>>> to > > > >>> CDI. > > > >>>>> * Introduce a PostConstruct and PreDestroy annotation because later > > > >>>>> versions of Java removed them from the base JDK (they're in a > > > >>>>> separate > > > >>>>> module from java.base), and javax.inject is supposed to support > > > >>>>> those > > > >>>>> annotations. > > > >>>>> * Introduce a "Configuration" scope which lives for the life of a > > > >>>>> configuration. This would essentially replace the concept of a > > > >>>>> "core" > > > >>>>> plugin category as they map to the lifecycle of a configuration > > > >>>>> source. > > > >>>>> * Use the "Singleton" scope for anything we'd want to live for the > > > >>>>> entire application instance (generally replaces use of system > > > >>>>> property > > > >>>>> singletons where possible). > > > >>>>> * Integrate some common scopes like request-scoped, session-scoped, > > > >>>>> etc., to allow for a more pluggable system for introducing scopes > > > >>>>> for > > > >>>>> Lookups or other plugins. > > > >>>>> * Use the PostConstruct/PreDestroy callbacks to replace initialize > > > >>>>> and > > > >>>>> destroy methods in plugins. This might work well toward generic > > > >>>>> lifecycle management which is currently done ad hoc. > > > >>>>> * I have a vague notion that a "LogEvent" scope would be really > > > >>>>> neat, > > > >>>>> but such a system would likely not work well with GC-free code, so > > > >>>>> I'm > > > >>>>> not really considering this one at the moment. > > > >>>>> * PluginAttribute/PluginBuilderAttribute/PluginElement/PluginValue > > > >>>>> all > > > >>>>> become stereotype qualifiers with some annotation compatibility > > > >>>>> checks > > > >>>>> to support old annotations. > > > >>>>> * PluginFactory becomes a stereotype producer annotation. > > > >>>>> * PluginBuilderFactory (previously deleted) would also be a > > > >>>>> stereotype > > > >>>>> producer annotation. > > > >>>>> > > > >>>>> One thing I'm experimenting with right now that should really help > > > >>>>> inform me whether or not this effort will be worth it is breaking > > > >>>>> this > > > >>>>> down into an SPI that will have two default implementations: one > > > >>>>> based > > > >>>>> on runtime reflection, and another based on generated code from the > > > >>>>> annotation processor (a more advanced version of the existing > > > >>>>> PluginService code generator). I hope to avoid the use of actual > > > >>>>> reflection APIs in the generated code to more easily support GraalVM > > > >>>>> as well as to hopefully offload a bit of the reflective > > > >>>>> initialization > > > >>>>> to compile-time rather than at runtime (fairly useful for > > > >>>>> microservices where startup time is more important). > > > >>>>> > > > >>>>> I do have an overarching purpose behind all this: I'd like to > > > >>>>> dramatically reduce the tight coupling between Configuration, Node, > > > >>>>> and plugin classes. Some of this is in the form of a more generic > > > >>>>> dependency injection API to avoid the need for manually calling > > > >>>>> Configuration methods in plugin factories. Another is to make > > > >>>>> various > > > >>>>> services provided by Configuration to instead be injected directly > > > >>>>> as > > > >>>>> parameters to the plugin factories. Reducing the coupling between > > > >>>>> plugins and other running parts of the system should help reduce the > > > >>>>> complexity of many tests as well, and it may also help reduce the > > > >>>>> time > > > >>>>> taken running tests, though that will still likely be affected by > > > >>>>> the > > > >>>>> various integration tests regardless. > > > >>>>> > > > >>>>> On Wed, 9 Oct 2019 at 16:52, Matt Sicker <boa...@gmail.com> wrote: > > > >>>>>> > > > >>>>>> Part of this is to make it simpler to access globally configured > > > >>>>>> things without having to pass around a Configuration everywhere. If > > > >>>>>> plugins can declare the explicit parts of the API they need access > > > >>>>>> to > > > >>>>>> rather than the full Configuration, that should make tests a bit > > > >>>>>> lighter and easier to write. > > > >>>>>> > > > >>>>>> On Wed, 9 Oct 2019 at 16:11, Ralph Goers > > > >>>>>> <ralph.go...@dslextreme.com> > > > >>> wrote: > > > >>>>>>> > > > >>>>>>> FWIW, I don’t think @Inject is a good replacement for > > > >>> @PluginFactory. @Inject is essentially the same as @Autowired. It > > > >>> should > > > >>> be placed on fields where you want the implementation to be injected. > > > >>> @Inject specified on a method implies that the method parameters > > > >>> should be > > > >>> injected. I don’t think that is what you are intending. > > > >>>>>>> > > > >>>>>>> Ralph > > > >>>>>>> > > > >>>>>>>> On Oct 9, 2019, at 1:38 PM, Ralph Goers > > > >>>>>>>> <ralph.go...@dslextreme.com> > > > >>> wrote: > > > >>>>>>>> > > > >>>>>>>> Ok, but given @Scope and @Qualifier can only be used to annotate > > > >>> the existing PluginElement, PluginAttribute and PluginValue > > > >>> annotations I > > > >>> am not sure what they buy you. They can’t be used to replace the > > > >>> existing > > > >>> annotations as they are only allowed to be used on annotation > > > >>> declarations. I agree that @PluginConfiguration is somewhat > > > >>> redundant. All > > > >>> we are really doing with it is saying that the existing Configuration > > > >>> object should be passed to the method. Using @PluginConfiguration for > > > >>> that > > > >>> is easy but using @Inject as an indicator and checking the type of the > > > >>> parameter could just as easily be done. > > > >>>>>>>> > > > >>>>>>>> I guess I would like to see what you think an example plugin > > > >>>>>>>> would > > > >>> look like before going further. > > > >>>>>>>> > > > >>>>>>>> Ralph > > > >>>>>>>> > > > >>>>>>>> > > > >>>>>>>> > > > >>>>>>>>> On Oct 9, 2019, at 11:46 AM, Matt Sicker <boa...@gmail.com> > > > >>>>>>>>> wrote: > > > >>>>>>>>> > > > >>>>>>>>> I want to make it simpler to write plugins. Increase > > > >>>>>>>>> testability, > > > >>> reuse > > > >>>>>>>>> more standard APIs that others would be more familiar with > > > >>>>>>>>> (easier > > > >>>>>>>>> onboarding), and make it simpler to implement some tangentially > > > >>> related > > > >>>>>>>>> feature ideas. > > > >>>>>>>>> > > > >>>>>>>>> As for the builder versus factory annotation, there was already > > > >>> special > > > >>>>>>>>> support for collections and maps that weren’t explicit > > > >>> annotations, so > > > >>>>>>>>> determining what to do based on the return type of the factory > > > >>> method was > > > >>>>>>>>> already an established idea. I think it made sense to combine > > > >>>>>>>>> them > > > >>> all into > > > >>>>>>>>> @PluginFactory, and because of that, I noticed the > > > >>>>>>>>> correspondence > > > >>> between > > > >>>>>>>>> that and @Inject. > > > >>>>>>>>> > > > >>>>>>>>> On Wed, Oct 9, 2019 at 13:28, Ralph Goers < > > > >>> ralph.go...@dslextreme.com> > > > >>>>>>>>> wrote: > > > >>>>>>>>> > > > >>>>>>>>>> I still don’t understand what the benefit is. IIUC your plan is > > > >>> to add the > > > >>>>>>>>>> @Scope and @Qualifier annotations to the @PluginElement and > > > >>>>>>>>>> @PluginAttribute. If that somehow helps, great, as it is will > > > >>>>>>>>>> be > > > >>> invisible > > > >>>>>>>>>> to plugin developers. > > > >>>>>>>>>> > > > >>>>>>>>>> One thing I find odd is that Builders were annotated with > > > >>>>>>>>>> @PluginBuilderFactory and are now annotated with > > > >>>>>>>>>> @PluginFactory. > > > >>>>>>>>>> Previously, only factory methods were annotated with > > > >>> @PluginFactory. What > > > >>>>>>>>>> is odd is that the methods previously annotated with > > > >>> @PluginBuilderFactory > > > >>>>>>>>>> create a Builder. They builder then creates the plugin object. > > > >>> However the > > > >>>>>>>>>> methods annotated with @PluginFactory directly created the > > > >>>>>>>>>> plugin > > > >>> object. > > > >>>>>>>>>> Now you have both annotated with @PluginFactory, which means > > > >>>>>>>>>> some > > > >>> methods > > > >>>>>>>>>> behave one way and others behave another way. How is that > > > >>>>>>>>>> clearer? > > > >>>>>>>>>> > > > >>>>>>>>>> That said changing both to @Inject has some merit although I am > > > >>> not sure > > > >>>>>>>>>> how you are determining that one is creating a Builder that > > > >>>>>>>>>> then > > > >>> creates > > > >>>>>>>>>> the object vs a method that creates the object. > > > >>>>>>>>>> > > > >>>>>>>>>> But again, what problem is this trying to solve? How will this > > > >>> make things > > > >>>>>>>>>> easier for users? > > > >>>>>>>>>> > > > >>>>>>>>>> Ralph > > > >>>>>>>>>> > > > >>>>>>>>>> > > > >>>>>>>>>> > > > >>>>>>>>>> > > > >>>>>>>>>>> On Oct 9, 2019, at 10:42 AM, Matt Sicker <boa...@gmail.com> > > > >>> wrote: > > > >>>>>>>>>>> > > > >>>>>>>>>>> To clarify on the mapping between javax.inject and the > > > >>>>>>>>>>> existing > > > >>>>>>>>>>> annotations, I believe this would work: > > > >>>>>>>>>>> > > > >>>>>>>>>>> @PluginFactory can be replaced by @Inject > > > >>>>>>>>>>> @PluginElement is a @Scope annotation > > > >>>>>>>>>>> @PluginAttribute is a @Qualifier annotation > > > >>>>>>>>>>> @PluginConfiguration could be a scope or singleton, but it's > > > >>> redundant > > > >>>>>>>>>>> @PluginNode could be a scope, but it's somewhat redundant > > > >>>>>>>>>>> @PluginValue would be a @Qualifier > > > >>>>>>>>>>> > > > >>>>>>>>>>> On Wed, 9 Oct 2019 at 10:05, Matt Sicker <boa...@gmail.com> > > > >>> wrote: > > > >>>>>>>>>>>> > > > >>>>>>>>>>>> Ok, I see the issue. I won’t add a dependency on the API. I > > > >>>>>>>>>>>> do > > > >>> want to > > > >>>>>>>>>> try refactoring the 3.x API to use an annotation model similar > > > >>>>>>>>>> to > > > >>> that. > > > >>>>>>>>>> I’ll show a proof of concept sometime soon. > > > >>>>>>>>>>>> > > > >>>>>>>>>>>> On Tue, Oct 8, 2019 at 18:50, Ralph Goers < > > > >>> ralph.go...@dslextreme.com> > > > >>>>>>>>>> wrote: > > > >>>>>>>>>>>>> > > > >>>>>>>>>>>>> I don’t understand. You can’t add javax.inject stuff into > > > >>>>>>>>>>>>> our > > > >>>>>>>>>> namespace without changing the package name. And if you change > > > >>> the package > > > >>>>>>>>>> name I don’t see any benefit at all as the current names are > > > >>>>>>>>>> much > > > >>> clearer. > > > >>>>>>>>>>>>> > > > >>>>>>>>>>>>> I have no problem with Configurations being a plugin except > > > >>>>>>>>>>>>> it > > > >>> will > > > >>>>>>>>>> currently cause an endless loop as plugins are captured during > > > >>>>>>>>>> configuration. So any change you make here is going to be huge. > > > >>>>>>>>>>>>> > > > >>>>>>>>>>>>> Ralph > > > >>>>>>>>>>>>> > > > >>>>>>>>>>>>>> On Oct 8, 2019, at 2:23 PM, Matt Sicker <boa...@gmail.com> > > > >>> wrote: > > > >>>>>>>>>>>>>> > > > >>>>>>>>>>>>>> I'm thinking that the old annotations can be supported in > > > >>> terms of the > > > >>>>>>>>>>>>>> javax.inject API. As for requiring a jar, that's why I've > > > >>>>>>>>>>>>>> also > > > >>>>>>>>>>>>>> suggested just adopting the annotations into our own > > > >>>>>>>>>>>>>> package > > > >>>>>>>>>>>>>> somewhere. > > > >>>>>>>>>>>>>> > > > >>>>>>>>>>>>>> Either way this is done, my general goal is to untangle > > > >>>>>>>>>>>>>> other > > > >>> areas in > > > >>>>>>>>>>>>>> the core API that could benefit from generic DI support. > > > >>>>>>>>>>>>>> See > > > >>> for > > > >>>>>>>>>>>>>> example turning Configuration into a plugin. > > > >>>>>>>>>>>>>> > > > >>>>>>>>>>>>>> On Tue, 8 Oct 2019 at 15:40, Ralph Goers < > > > >>> ralph.go...@dslextreme.com> > > > >>>>>>>>>> wrote: > > > >>>>>>>>>>>>>>> > > > >>>>>>>>>>>>>>> I don’t see how that relates. The proposal as I understand > > > >>> it is to > > > >>>>>>>>>> replace the existing annotations with annotations from > > > >>> javax.inject, which > > > >>>>>>>>>> would require a JEE jar. > > > >>>>>>>>>>>>>>> > > > >>>>>>>>>>>>>>> Ralph > > > >>>>>>>>>>>>>>> > > > >>>>>>>>>>>>>>>> On Oct 8, 2019, at 1:31 PM, Jochen Wiedmann < > > > >>>>>>>>>> jochen.wiedm...@gmail.com> wrote: > > > >>>>>>>>>>>>>>>> > > > >>>>>>>>>>>>>>>> On Tue, Oct 8, 2019 at 10:26 PM Ralph Goers < > > > >>>>>>>>>> ralph.go...@dslextreme.com> wrote: > > > >>>>>>>>>>>>>>>>> > > > >>>>>>>>>>>>>>>>> IIUC this will require a dependency on a Java EE jar? > > > >>>>>>>>>>>>>>>>> For > > > >>> that > > > >>>>>>>>>> reason alone, no. > > > >>>>>>>>>>>>>>>> > > > >>>>>>>>>>>>>>>> Don't think so. A simple (mostly JSR 330 compliant) > > > >>> provider can be > > > >>>>>>>>>>>>>>>> implemented in a few classes: > > > >>>>>>>>>>>>>>>> > > > >>>>>>>>>>>>>>>> > > > >>>>>>>>>> > > > >>> https://github.com/jochenw/afw/tree/master/afw-core/src/main/java/com/github/jochenw/afw/core/inject/simple > > > >>>>>>>>>>>>>>>> > > > >>>>>>>>>>>>>>> > > > >>>>>>>>>>>>>>> > > > >>>>>>>>>>>>>> > > > >>>>>>>>>>>>>> > > > >>>>>>>>>>>>>> -- > > > >>>>>>>>>>>>>> Matt Sicker <boa...@gmail.com> > > > >>>>>>>>>>>>>> > > > >>>>>>>>>>>>> > > > >>>>>>>>>>>>> > > > >>>>>>>>>>>> -- > > > >>>>>>>>>>>> Matt Sicker <boa...@gmail.com> > > > >>>>>>>>>>> > > > >>>>>>>>>>> > > > >>>>>>>>>>> > > > >>>>>>>>>>> -- > > > >>>>>>>>>>> Matt Sicker <boa...@gmail.com> > > > >>>>>>>>>>> > > > >>>>>>>>>> > > > >>>>>>>>>> > > > >>>>>>>>>> -- > > > >>>>>>>>> Matt Sicker <boa...@gmail.com> > > > >>>>>>>> > > > >>>>>>>> > > > >>>>>>>> > > > >>>>>>> > > > >>>>>>> > > > >>>>>> > > > >>>>>> > > > >>>>>> -- > > > >>>>>> Matt Sicker <boa...@gmail.com> > > > >>>>> > > > >>>>> > > > >>>>> > > > >>>>> -- > > > >>>>> Matt Sicker <boa...@gmail.com> > > > >>>> > > > >>>> > > > >>>> > > > >>>> -- > > > >>>> Matt Sicker <boa...@gmail.com> > > > >>>> > > > >>> > > > >>> -- > > > >> Matt Sicker <boa...@gmail.com> > > > >> > > > > -- > > > > Matt Sicker <boa...@gmail.com> > > > > > > > > > > > > -- > > Matt Sicker <boa...@gmail.com> > > > > -- > Matt Sicker <boa...@gmail.com> -- Matt Sicker <boa...@gmail.com>