Dave, Per our discussion in trying to get the signet hooks to look like grouper hooks as far as an institution hook implementer would be concerned... Here are some links to grouper hooks stuff that you can model off of: Here is how to configure a Grouper hook: https://wiki.internet2.edu/confluence/display/GrouperWG/Hooks See the hooks section in the config file: http://viewvc.internet2.edu/viewvc.py/grouper/conf/grouper.example.properties?root=I2MI&view=markup You can comma-separate the hooks classes (this can be optional). Note there are 10 hooks classes, and all hook methods are inside Here are the hooks classes to subclass: http://viewvc.internet2.edu/viewvc.py/grouper/src/grouper/edu/internet2/middleware/grouper/hooks/?root=I2MI Note that that package is only used for hooks superclasses, and all the classes end in "Hooks" Here is a look inside one of them: http://viewvc.internet2.edu/viewvc.py/grouper/src/grouper/edu/internet2/middleware/grouper/hooks/GroupHooks.java?root=I2MI&view=markup Note the method signature: public void groupPreUpdate(HooksContext hooksContext, HooksGroupBean preUpdateBean) { } It takes a context bean first, then a bean for data resulting from this hook, and it is a void method. The fact that this is an abstract class and not an interface means that if we add a hook, we don’t have to tell people to recompile. The fact that the context and arguments to the hook are in two beans means that if we add a parameter, we don’t have to tell people to recompile. The name of a pre hook is "groupPreUpdate", the name of a post commit hook is: "groupPostCommitUpdate". Might want to make the inside of HooksContext similar: http://viewvc.internet2.edu/viewvc.py/grouper/src/grouper/edu/internet2/middleware/grouper/hooks/beans/HooksContext.java?root=I2MI&view=markup Note it holds which application is running (e.g. web service, ui, gsh), and the user logged in, user act as, etc. It has space for stuff which is thread safe (synchronous only), and any thread (synchronous and asynchronous). To veto, a hook throws a HookVeto which has a reason text and reason key: http://viewvc.internet2.edu/viewvc.py/grouper/src/grouper/edu/internet2/middleware/grouper/hooks/logic/HookVeto.java?root=I2MI&view=markup In grouper you can run asynchronous logic by adding a marker interface to the hooks subclass implementation, or by calling inverse of control (if you use the interface, Grouper uses the inverse of control under the covers). So simplify, I suggest, only having the interface. But up to you: http://viewvc.internet2.edu/viewvc.py/grouper/src/grouper/edu/internet2/middleware/grouper/hooks/logic/HookAsynchronousMarker.java?root=I2MI&view=markup http://viewvc.internet2.edu/viewvc.py/grouper/src/grouper/edu/internet2/middleware/grouper/hooks/logic/HookAsynchronousHandler.java?root=I2MI&view=markup (this class isn’t trivial, so you might be able to get something from it): http://viewvc.internet2.edu/viewvc.py/grouper/src/grouper/edu/internet2/middleware/grouper/hooks/logic/HookAsynchronous.java?revision=1.6&root=I2MI&view=markup This is an implementation detail, but each hook type has its own enum to configure it. Note this implements an interface so extensions could register their own hook type: http://viewvc.internet2.edu/viewvc.py/grouper/src/grouper/edu/internet2/middleware/grouper/hooks/logic/GrouperHookType.java?root=I2MI&view=markup This class is not huge, but it is a little time consuming to create, so maybe you can get something from it. It allows the Grouper API to call any registered hooks in one line of code. Also it caches hooks to the method level so it doesn’t call any hooks which don’t exist (e.g. if an implementation overrides a hook class and only implements one method): http://viewvc.internet2.edu/viewvc.py/grouper/src/grouper/edu/internet2/middleware/grouper/hooks/logic/GrouperHooksUtils.java?revision=1.13&root=I2MI&view=markup I made an examples package inside of grouper so people will have examples that work, or maybe that are useful for grouper (e.g. the grouper attribute value regex hook). I think this is a good idea to have: http://viewvc.internet2.edu/viewvc.py/grouper/src/grouper/edu/internet2/middleware/grouper/hooks/examples/?root=I2MI The way to make hooks low impact to the API is the one line call. E.g. http://viewvc.internet2.edu/viewvc.py/grouper/src/grouper/edu/internet2/middleware/grouper/Group.java?root=I2MI&view=markup GrouperHooksUtils.callHooksIfRegistered(this, GrouperHookType.GROUP, GroupHooks.METHOD_GROUP_PRE_INSERT, HooksGroupBean.class, this, Group.class, VetoTypeGrouper.GROUP_PRE_INSERT, false, false); This line will call any pre insert hooks if registered... Another important thing about Grouper hooks which is a complication, but that I think is valuable is that Grouper has an API wrapped around Hibernate. See the hibernate package. http://viewvc.internet2.edu/viewvc.py/grouper/src/grouper/edu/internet2/middleware/grouper/hibernate/?root=I2MI An example of using this is: hibernateSession.byObject().delete( _s ); Inside the hibernate api, we kick off callbacks to the object: if (!this.isIgnoreHooks() && object instanceof HibGrouperLifecycle) { ((HibGrouperLifecycle)object).onPreDelete(hibernateSession); } session.delete(object); if (!this.isIgnoreHooks() && object instanceof HibGrouperLifecycle) { ((HibGrouperLifecycle)object).onPostDelete(hibernateSession); } In the callback, we call hooks if registered: public void onPreDelete(HibernateSession hibernateSession) { super.onPreDelete(hibernateSession); GrouperHooksUtils.callHooksIfRegistered(this, GrouperHookType.GROUP, GroupHooks.METHOD_GROUP_PRE_DELETE, HooksGroupBean.class, this, Group.class, VetoTypeGrouper.GROUP_PRE_DELETE, false, false); } Anyways, there are lots of ways to do this (wrapping the hibernate logic), not only the way I did it, but my point is, is that anywhere in the API where we use the hibernate wrapper code, the hooks get kicked off. If we used hibernate directly everywhere, then we would have to go through and make sure that the hooks are being fired off correctly. In the Hooks wiki above, there is a logging section would be useful to have similar between signet and grouper, here is an example output: 2008/07/09 02:18:05.482 GrouperHooksUtils.executeHook(174) - START: Hook GroupTypeTupleHooksImpl.groupTypeTuplePreInsert id: PSPTRJ8J 2008/07/09 02:18:05.497 GrouperHooksUtils.executeHook(181) - END (normal): Hook GroupTypeTupleHooksImpl.groupTypeTuplePreInsert id: PSPTRJ8J (15ms) 2008/07/09 02:18:05.497 GrouperHooksUtils.executeHook(174) - START: Hook GroupTypeTupleHooksImpl.groupTypeTuplePostInsert id: PSPTRJ8K 2008/07/09 02:18:05.497 GrouperHooksUtils.executeHook(186) - END (veto): Hook GroupTypeTupleHooksImpl.groupTypeTuplePostInsert id: PSPTRJ8K (0ms), veto key: hook.veto.groupTypeTuple.insert.name.not.test4, veto message: name cannot be test4 Finally, each hook method (more than 80) is unit tested: http://viewvc.internet2.edu/viewvc.py/grouper/src/test/edu/internet2/middleware/grouper/hooks/?root=I2MI See the hooks tests for each hook method, and the test implementation of the hook. The asynchronous ones are tested, etc. Hope this helps, good luck! Chris