Den 18-12-2015 kl. 03:16 skrev Niclas Hedhman: > Kent, > I saw your EventBus work, and I would be happy if you could elaborate on > the mechanics. > > For instance, to me it felt a bit "strange" that the EventType declares its > handler type, instead of the handler declaring the event type. I guess that > you have some reason for this, even if I can't see it.
The EventBus concept is inspired from working with GWT, that has a similar (but more complex) concept. Basically the bus itself is unaware of the concrete types of events and HOW to dispatch those to handlers - it only needs to know how to find out WHICH handlers to invoke. For each type of event there are 3 parts The TYPE (a singleton object pr type of event) The Event class (allows discovery of it's TYPE and are itself able to dispatch to a specific handler) The EventHandler - this is registered inside the bus with the TYPE. Eventhandlers are registered inside the bus together with a TYPE. When an event is received, the bus asks for it's TYPE, use that information to find the relevant handlers, and let the event itself dispatch to each of those handlers. The EventBus has thus no knowledge of concrete events and how to handle those - more can be added later, it is just a matter of who gains access to the EventBus. Currently there are these types of events: ZestRuntimeEvent: Thrown and handled by the runtime ZestUserEvent: Thrown by the runtime, handled by usercode. - ZestAssemblyEvent: A ZestUserEvent thrown during assembly - ZestApplicationEvent: A ZestUserEvent thrown during runtime operations. Handlers for ZestRuntimeEvent are added by the runtime itself - this is currently done inside the EventBus itself, but will probably be moved later. Application code can add handlers for all kinds of ZestUserEvent *before* assembly. Application code can add handlers ZestApplicationEvent *during* assembly. It is currently not possible for application writers to emit events - but it is simply a matter of visibility (we could eg. add an emit() method to the ZestAPI interface). This can already be used by adding handlers during assembly - an handler could eg add an extra service to each module in the application. - or customize an existing composite, eg by adding a concern to it. The current usage is that UnitOfWorkStuff is added to each module before any user code is triggered - the user may use handlers to customize this later. This should probably later be enhanced to - let the user add UnitOfWork "stuff" - let the framework add it if not already there (this Assembly does currently not expose the answer to that question) - "do all the module specific stuff as we are used to" - The user can customize the UnitOfWorkStuff late in the process, regardless of whether it is his own mixin implementation or the built-in one. Currently the addition of "core handlers" is done by the EventBus itself - the main reason was that it allowed me an easy way to emit events from these handlers - which i think should not be generally possibly to avoid complicating things too much. The eventbus itself is definitely NOT a permanent location for this. > Another thing, instead of going via the event route (which for me feels a > bit misplaced for Assembly), we could instead add methods, > > addServices( boolean ifExists, Class<?>... services) > addEntities( boolean ifExists, Class<?>... services) > addValues( boolean ifExists, Class<?>... services) > addTransients( boolean ifExists, Class<?>... services) > addObjects( boolean ifExists, Class<?>... services) > > in LayerAssembly and ApplicationAssembly classes. It could be another way of adding composites to all modules My main reasoning for not doing that was a fear of exploding the API - basically i was unable to see where to stop (which methods should not be added). This could soon lead to almost public interface ApplicationAssembly extend ModuleAssembly Another reasoning for going the event route is a belief, that we can use this mechanism for the existing lifecycle stuff too (the activation stuff). An example could be let the moduleInstance emit an activate() event and let handlers figure out the meaning of this (activate relevant services). I believe this could be a path towards separating the core into an essential "micro-kernel" and useful (but not strictly essential) stuff which are added as a convenience. I also believe it could be a step towards making addition of new composite types easier. /Kent
