Hello Berin, Shash and All! :-) 1. ===========================================
SC> ... I now realize that the ServiceManager SC> interface has no "add/put/addService etc." method. One thing is that SC> Fortress could require the supplied service-manager to already have the SC> required services added Just as I read this mail from Shash an idea struck my head: Let's make ContextManager not final! This will allow Sash to subcall it and replace initializeServiceManager with whatever he likes, voi'la! One more point of extensibility (and a very powerfull one :-) Since DefaultContainerManager has a constructor that accepts ContextManager I understand that such usage pattern has probably been forseen before. 2. =========================================== While implementing this couldn't overcome one problem. If we have class Abstract { protected Great createGreat() { DefaultGreat great = new DefaultGreat(); great.put( foo ); great.put( bar ); great.makeReadOnly(); return great; } } it is not that easy to override createGreat(): * one option is to duplicate all the code from Abstract.createGreat() SC> (but it could have issues with later maintenance) as Shash has correctly remarked. * another option is to wrap the Great returned from parent in another DefaultGreat like class Derived extends Abstract { protected Great createGreat() { Great parent = super.createGreat(); DefaultGreat great = new DefaultGreat( parent ); great.put( blah ); great.makeReadOnly(); return great; } } but this does not look too nice to me either, we're creating an unnecessary hierarchy here This patch proposes the following solution (I beleive it may turn to be quite a general solution: class Abstract { protected void initializeGreat() { m_great = createGreat(); FortressUtil.makeReadOnly( m_great ); } protected Great createGreat() { DefaultGreat great = new DefaultGreat(); great.put( foo ); great.put( bar ); return great; } } class Derived extends Abstract { protected Great createGreat() { DefaultGreat great = (DefaultGreat) super.createGreat(); great.put( blah ); return great; } } It's a pity we need to know the exact class retuned by super.creatGreat() for this, but it's a tradeoff. Moreover, if we want to code defensively we might do class Derived extends Abstract { protected Great createGreat() { Great parent = (DefaultGreat) super.createGreat(); DefaultGreat great; if ( parent instanceof DefaultGreat ) { great = (DefaultGreat) parent; } else { great = new DefaultGreat( parent ); } great.put( blah ); return great; } } This sort of gives us best of two worlds :-) 3. ================================================ Sure, this patch includes all what was in Patch #14 - provideLifecycleExtensions() method to allow derived containers manage their personal lifecycle extensions. (The global lifecycle extensions are managed by passing a LifecycleExtensionManager to FortressConfig and down the pipleline) I beleive this will the extension (and experimentation) path with Fortress smoother. BL> As this does not refer to a bug, I think I would like to focus on a BL> Fortress 1.0 release. We can apply this and whatever other patches BL> for the next release (which can be soon afterwards if we want). BL> All, I think we are reaching the point where we are delaying Fortress BL> without resolving bugs. While all the patches are generally good, and BL> we would like to make it into Fortress, do we think that Fortress is BL> Good Enough(TM) to release now? This ll sounds good to me (TM :), but since a new release candidate has not been rolled out yet, maybe we'll incorporate this too? People will start experimenting with Fortress and I would rather give them a smoth path to do it. Of course, code is freezed at relase cycle to shake out bugs, but can we hope that these changes are so incremental and so starightforward that they don't introduce any new? With a will to get this patch in and without a will to create any new before the release - Anton Tagunov Only in fortress/src/java/org/apache/avalon/fortress: ReadOnly.java Only in fortress/src/java/org/apache/avalon/fortress: WriteProtectable.java diff -ru fortress.cvs/src/java/org/apache/avalon/fortress/impl/AbstractContainer.java fortress/src/java/org/apache/avalon/fortress/impl/AbstractContainer.java --- fortress.cvs/src/java/org/apache/avalon/fortress/impl/AbstractContainer.java 2003-05-29 22:09:54.000000000 +0400 +++ fortress/src/java/org/apache/avalon/fortress/impl/AbstractContainer.java 2003-05-30 13:06:39.000000000 +0400 @@ -63,6 +63,7 @@ import org.apache.avalon.fortress.impl.lookup.FortressServiceSelector; import org.apache.avalon.fortress.util.CompositeException; import org.apache.avalon.fortress.util.LifecycleExtensionManager; +import org.apache.avalon.fortress.util.FortressUtil; import org.apache.avalon.fortress.util.dag.CyclicDependencyException; import org.apache.avalon.fortress.util.dag.DirectedAcyclicGraphVerifier; import org.apache.avalon.fortress.util.dag.Vertex; @@ -285,18 +286,14 @@ extLogger.debug( message ); } - /** - * We do need a new InstrumentableCreator, as we want strictly our - * m_instrumentManager to be engaged. We assume there is no - * InstrumentableCreator in the LifecycleExtensionManager passed to us - * already. If there is one this is probably a bug. Not testing this currently, - * although might test this in the future in order to - * throw something like an IllegalArgumentException. + /** + * m_extManager remains writeable until makeEntitiesReadOnly() is invoked + * in initialize(). Before that derived container implementations are + * free to manipulate it. Overriding provideLifecycleExtensions() method + * invoked from initialize() is the preferred way to do that. Note + * that the overriden AbstractContainer.provideLifecycleExtensions() + * method should still be invoked from the overriding one. */ - m_extManager.addCreatorExtension( new InstrumentableCreator( m_instrumentManager ) ); - - // just to be on the safe side - m_extManager.makeReadOnly(); } /** @@ -615,6 +612,11 @@ public void initialize() throws CompositeException, Exception { + /* Manager lifecycle extensions. */ + provideLifecycleExtensions( m_extManager ); + + makeOurServicesReadOnly(); + // go over all components final Iterator i = m_components.iterator(); final BoundedFifoBuffer buffer = new BoundedFifoBuffer( Math.max( m_components.size(), 1 ) ); @@ -772,6 +774,16 @@ } /** + * Make read only the objects we have created. + */ + protected void makeOurServicesReadOnly() + { + FortressUtil.makeReadOnly( m_extManager ); + FortressUtil.makeReadOnly( m_serviceManager ); + FortressUtil.makeReadOnly( m_componentContext ); + } + + /** * Disposes of all components and frees resources that they consume. */ public void dispose() @@ -852,4 +864,33 @@ /* the default implementation: just use the same as for container itself */ return parent; } + + /** + * Override his method to manage the set of lifecycle extensions. + * As the contract of managing lifecycle extensions has not solidified + * yet this method allowes you do anything with the set of extensions + * supplied by our manager (container manager or parent container): + * add and remove them as you like. Note however that + * InstrumentableCreatro should always be added as in this default + * implementation not to upset the Instrumentable and InstrumentManageable + * components we will create. + * This method is called from withing initialize(). + * @param extManager a copy of the LifecycleExtensionManager provided by + * our manager (container manager or parent container) + * or a new empty one if none has been provided. + */ + protected void provideLifecycleExtensions( final LifecycleExtensionManager extManager ) + throws Exception + { + /** + * AbstractContainer adds only one extension, the InstrumentableCreator. + * We do need a new InstrumentableCreator, as we want strictly our + * m_instrumentManager to be engaged. We assume there is no + * InstrumentableCreator in the LifecycleExtensionManager passed to us + * already. If there is one this is probably a bug. Not testing this currently, + * although might test this in the future in order to + * throw something like an IllegalArgumentException. + */ + extManager.addCreatorExtension( new InstrumentableCreator( m_instrumentManager ) ); + } } diff -ru fortress.cvs/src/java/org/apache/avalon/fortress/impl/lookup/FortressServiceManager.java fortress/src/java/org/apache/avalon/fortress/impl/lookup/FortressServiceManager.java --- fortress.cvs/src/java/org/apache/avalon/fortress/impl/lookup/FortressServiceManager.java 2003-05-15 12:11:18.000000000 +0400 +++ fortress/src/java/org/apache/avalon/fortress/impl/lookup/FortressServiceManager.java 2003-05-30 12:45:13.000000000 +0400 @@ -52,6 +52,7 @@ import org.apache.avalon.fortress.Container; import org.apache.avalon.fortress.impl.AbstractContainer; import org.apache.avalon.fortress.impl.handler.ComponentHandler; +import org.apache.avalon.fortress.ReadOnly; import org.apache.avalon.framework.component.ComponentSelector; import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; @@ -70,7 +71,7 @@ * @version CVS $Revision: 1.17 $ $Date: 2003/05/14 15:54:46 $ */ public class FortressServiceManager - implements ServiceManager + implements ServiceManager, ReadOnly { private final Container m_container; private final Map m_used; diff -ru fortress.cvs/src/java/org/apache/avalon/fortress/util/ContextManager.java fortress/src/java/org/apache/avalon/fortress/util/ContextManager.java --- fortress.cvs/src/java/org/apache/avalon/fortress/util/ContextManager.java 2003-05-29 22:10:06.000000000 +0400 +++ fortress/src/java/org/apache/avalon/fortress/util/ContextManager.java 2003-05-30 12:56:23.000000000 +0400 @@ -120,7 +120,7 @@ * @version CVS $Revision: 1.34 $ $Date: 2003/05/29 13:15:06 $ * @since 4.1 */ -public final class ContextManager +public class ContextManager implements ContextManagerConstants, Initializable, Disposable { private static final Configuration EMPTY_CONFIG; @@ -680,6 +680,21 @@ protected void initializeServiceManager() throws Exception { final ServiceManager parent = (ServiceManager) get( m_rootContext, SERVICE_MANAGER, null ); + final ServiceManager manager = createServiceManager( parent ); + FortressUtil.makeReadOnly( manager ); + m_containerManagerContext.put( SERVICE_MANAGER, manager ); + } + + /** + * Override this method to create the ServiceManager up to your preference. + * Don't make it readonly in this method, instead use a DefaulServiceManager + * or derive your service manager from the WriteProtectable interface and + * it will be made read only for you later. This is to allow derived + * implementations to call <code>manager = super.createServiceManager()</code>, + * recast the obtained service manager to a concrete type and modify it. + */ + protected ServiceManager createServiceManager( final ServiceManager parent ) throws Exception + { final DefaultServiceManager manager = new DefaultServiceManager( parent ); /** @@ -705,9 +720,9 @@ manager.put( MetaInfoManager.ROLE, m_metaInfoManager ); manager.put( PoolManager.ROLE, m_poolManager ); manager.put( InstrumentManager.ROLE, m_instrumentManager ); - manager.makeReadOnly(); - m_containerManagerContext.put( SERVICE_MANAGER, manager ); + /* Will be made read-only in the invoking method. */ + return manager; } /** Only in fortress/src/java/org/apache/avalon/fortress/util: FortressUtil.java ======================org/apache/avalon/fortress/ReadOnly.java================ /* ============================================================================ The Apache Software License, Version 1.1 ============================================================================ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This product includes software developed by the Apache Software Foundation (http://www.apache.org/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 4. The names "Jakarta", "Avalon", "Excalibur" and "Apache Software Foundation" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact [EMAIL PROTECTED] 5. Products derived from this software may not be called "Apache", nor may "Apache" appear in their name, without prior written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation. For more information on the Apache Software Foundation, please see <http://www.apache.org/>. */ package org.apache.avalon.fortress; /** * An sibling interface to WriteProtectable. * It marks an object that is read-only since it has been * constructed by nature, like FortressRoleManager. * "ReadOnly" does not mean that behavior of this object * can not change, rather then it is only possible to * read data from this object, not write. * @see org.apache.avalon.fortress.util.FortressUtil */ public interface ReadOnly { } ======================org/apache/avalon/fortress/WriteProtectable.java================ /* ============================================================================ The Apache Software License, Version 1.1 ============================================================================ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This product includes software developed by the Apache Software Foundation (http://www.apache.org/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 4. The names "Jakarta", "Avalon", "Excalibur" and "Apache Software Foundation" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact [EMAIL PROTECTED] 5. Products derived from this software may not be called "Apache", nor may "Apache" appear in their name, without prior written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation. For more information on the Apache Software Foundation, please see <http://www.apache.org/>. */ package org.apache.avalon.fortress; /** * An interface to mark classes with makeReadOnly() method. * @see org.apache.avalon.fortress.util.FortressUtil */ public interface WriteProtectable { void makeReadOnly(); } ======================org/apache/avalon/fortress/util/FortressUtil.java========= /* ============================================================================ The Apache Software License, Version 1.1 ============================================================================ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This product includes software developed by the Apache Software Foundation (http://www.apache.org/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 4. The names "Jakarta", "Avalon", "Excalibur" and "Apache Software Foundation" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact [EMAIL PROTECTED] 5. Products derived from this software may not be called "Apache", nor may "Apache" appear in their name, without prior written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation. For more information on the Apache Software Foundation, please see <http://www.apache.org/>. */ package org.apache.avalon.fortress.util; import org.apache.avalon.framework.context.Context; import org.apache.avalon.framework.context.DefaultContext; import org.apache.avalon.framework.service.ServiceManager; import org.apache.avalon.framework.service.DefaultServiceManager; import org.apache.avalon.fortress.ReadOnly; import org.apache.avalon.fortress.WriteProtectable; /** * A gathering of usefull methods. * * The set of makeReadOnly methods tries to balance between * performance and convinience. A method is defined for each * concrete type that is known to have a makeReadOnly() method, * this method does not make any type checking. * * A method is defined for each general type we may need, this * method checks to see if it is a Default* implemnatation which * is known to have a makeReadOnly method and if it is a new * implementation that makes use of the WriteProtectable interface. * * No method is provided for the general Object type on purpose * to reduce the number of runtime type checkings. */ public class FortressUtil { /** * Convinience method to make the code look nicer. */ public static void makeReadOnly( final WriteProtectable protectable ) { protectable.makeReadOnly(); } /** * Convinience method to make the code look nicer. */ public static void makeReadOnly( final ReadOnly readOnly ) { /* no-op */ } /** * Convinience method to make the code look nicer. */ public static void makeReadOnly( final LifecycleExtensionManager manager ) { manager.makeReadOnly(); } /** * Convinience method to make the code look nicer. */ public static void makeReadOnly( final DefaultContext context ) { context.makeReadOnly(); } /** * Convinience method to make the code look nicer; * Performs some runtime type checking. */ public static void makeReadOnly( final Context context ) { if ( context instanceof DefaultContext ) { ((DefaultContext) context).makeReadOnly(); } else if ( context instanceof WriteProtectable ) { ((WriteProtectable) context).makeReadOnly(); } else if ( context instanceof ReadOnly ) { // no-op } else { failMakeReadOnly( context ); } } /** * Convinience method to make the code look nicer; * Performs some runtime type checking. */ public static void makeReadOnly( final ServiceManager manager ) { if ( manager instanceof DefaultServiceManager ) { ((DefaultServiceManager) manager).makeReadOnly(); } else if ( manager instanceof WriteProtectable ) { ((WriteProtectable) manager).makeReadOnly(); } else if ( manager instanceof ReadOnly ) { // no-op } else { failMakeReadOnly( manager ); } } private static void failMakeReadOnly( final Object obj ) { final String message = obj.getClass().getName() + " can't be made read only"; throw new IllegalArgumentException( message ); } } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]