here is a proposal that will allow us to: - have a well defined relationship between the container and component managers [though it doesn't touch on the issue of component resolving]
+ you could write component managers that will work in any container - and be specified at assembly time. + these new component managers will work alongside the existing component managers (allowing for a gentle upgrade path). - create dynamic proxies, for example: + tracing of component level method calls. + aaa (authentication, authorisation, and accounting), an aaa proxy could intercept component level method calls. + release() via the VM's garbage collector. + sessions could be implemented this way (with only slight modifications from my recent email). - possibly satisfy some of the need for custom markers (as long as they are called after initialize). [sessions would probably fit this category] - chain together any of the above (at the whim of the assembler). this will work with version 4 (and 5) of the framework and shouldn't break anything currently in existence. ==== proposal: CustomLookup interface ==== the proposal is simply that we add the following interface to the framework: interface CustomLookup { public Object lookup(); } with the contract: if a component implements the CustomLookup interface then upon ServiceManager.lookup() a reference to the component is not returned, but instead the result of the CustomLookup.lookup() method is returned. e.g. inside the ServiceManager the following: return component; could be replaced with: if ( component instanceof CustomLookup ) { return ((CustomLookup) component).lookup(); } else { return component; } Note: the CustomLookup should probably have a release() method that is deprecated/removed with the ServiceManager.release(). Note: the CustomLookup.lookup() has no args (to prevent it from being used as a selector/directory/resolver) I'd also like to make the following recommendation: in the absence of any other lifestyle indicator a component implementing CustomLookup should be a singleton, otherwise a new instance should be created upon every lookup. Note: the container will still have to be able to handle these two lifestyles (single and per-lookup) but all others can be managed by CustomLookup components. It shouldn't take much effort to implement this change. ==== example: component manager ==== note: component managers get the benefits of the lifecycle methods... for simplicity: not dealing with synchronization, exceptions, and assuming that release() will get called. class PoolingComponentManager implements CustomLookup, Parameterizable, Composable, Initializable { static final DEFAULT_SIZE = 5; String m_role; int m_size; List m_pool; ComponentManager m_cm; public void parameterize( Parameters parameters ) { m_size = parameters.getParameterAsInteger( "size", DEFAULT_SIZE ); m_role = parameters.getParameter( "role", null ); } public void Compose( ComponentManager cm ) { m_cm = cm; } public void initialize() { m_pool = new ArrayList( m_size ); } public Object lookup() { if (! m_pool.isEmpty() ) return m_pool.remove( 0 ); else return m_cm.lookup( m_role ); } public void release( Object component ) { if ( m_pool.size() < m_size ) { if ( component instanceof Recyclable ) ((Recyclable) component).recycle(); m_pool.add( component ); } else m_cm.release( component ); } } To use the PoolingComponentManager on a component X the assembler could do the following... 1. configure the pooling component manager so that it has parametes role=X-role size=5 2. configure the component locater so that a lookup that would have resolved to X now resolves to the pooling component manager. And that when the pooling component manager looks up X-role it gets X. Now whenever a client makes a request that would resolve to X, the request will go to the pooling component manager which will return a component from its pool or request X-role from the ComponentManager (if the pool is empty). ==== example: dynamic proxy ==== here is an example of how a tracing proxy could be implemented (minus exception handling and synchronization)... class TracingProxy extends AbstractLogEnabled implements CustomLookup, InvocationHandler, Composable, Parameterizable { String m_role; String m_name; ComponentManager m_cm; Map m_ids = new WeakHashMap(); int count = 0; public void parameterize( Parameters parameters ) { m_role = parameters.getParameter( "role", null ); m_name = parameters.getParameter( "name", "tracingProxy" ); } public void compose( ComponentManager cm ) { m_cm = cm; } public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable { Object ret; Object id = m_ids.get( proxy ); info( "Enter: " + method + " for " + m_name + "-" + id ); try { ret = method.invoke( m_component, args ); } catch ( InvocationTargetException ite ) { warn( "Error in: " + method " for " + m_name + "-" + id, ite ); throw ite.getTargetException(); } info( "Leave: " + method + " for " + m_name + "-" + id ); return ret; } public Object lookup() { Object component = m_cm.lookup( m_role ); Class[] interfaces = component.getClass().getInterfaces(); ClassLoader classLoader = component.getClass().getClassLoader(); Object proxy = java.lang.reflect.Proxy.newInstance( classLoader, interfaces, this ); m_ids.put( proxy, new Integer( ++m_count ) ); return proxy; } } To activate the tracing on a component X the assembler could do the following... 1. configure the tracing proxy so that it has parameters: role=X-role, name=X-trace 2. give the tracing proxy its own logger. 3. configure the component locator so that a lookup that would have resolved to X now resolves to the tracing proxy. And that whenever the tracing proxy looks up X-role it gets X. Now whenever a client makes a request that would resolve to X they will get a proxy that will log all method calls, before passing them on. ==== a SessionManagingProxy proxy can be created in a similar fashion to my recent email, with the change that the Proxy now runs the show (and the SessionEnabled component should probably let m_SessionManager default to an instance of SimpleSessionManager in case setSessionManager() isn't called). ==== issues ==== - it is now possible for the assembler to specify cyclic dependencies when chaining Customlookup components together, this may cause lookup() to hang. - unless you have something like: public Object lookup() { return this; } no other component will ever get a direct reference to the CustomLookup component. So I'm wondering if it is still correct to refer to it as a component... perhaps meta-component might be better... or since the dynamic proxies could fall into a broad definition of component management, perhaps manager-component... - I don't know if 'CustomLookup' is a great name so feel free to suggest others... MetaComponent? Robert. -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>