avalon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Anton Tagunov <atagu...@mail.cnt.ru>
Subject Re[2]: [Proposal] WriteProtectable/ReadOnly interfaces
Date Tue, 10 Jun 2003 12:47:21 GMT
Hello Niclas!

NH> Could you provide some reasoning around what you are trying to achieve?
Sure :-)

NH> You want to have a way to force that an object can no longer be modified, 
NH> after some point in time. The ReadOnly interface is intended as a marker that 
NH> an object can not be modified, and the WriteProtectable is an interface to 
NH> "turn on" the ReadOnly functionality.
yep!

NH> Provided this is the case, why do you need to "pollute" the Avalon Framework
NH> interfaces with such a construct?
only because I want to make all the classes that belong
to the framework that have .makeReadOnly() method to
implement this interface

NH> How do you see that the containers need to be involved in this scheme at all?
<disclaimer>I must confess I have been working only with Fortress,
so my experience is limited, and I will talk only about
Fortress</disclaimer>

I think that this will have its use in Fortress for instance.
The thing is that for for instance currently the AbstractContianer has
the following methods (submitted by me, that's why I concentrate
on them :-)

    protected ServiceManager provideServiceManager( final ServiceManager parent )
            throws ServiceException
    {
        return new FortressServiceManager( this, parent );
    }

    protected Context provideComponentContext( final Context parent )
            throws Exception
    {
        /* the default implementation: just use the same as for container itself */
        return parent;
    }

these are the extension points. Derived containers may override these
methods to deliver a different ServiceManager and/or Context to child
components.

Currently it is all okay, it is easy to subclass and override these
methods. But imagine that our subclassing hierarchy is going to
be one level deeper:

AbstractContainer - > DefaultContainer - > Custom0 - > Custom1

Imagine Custom0 overrides provideComponentContext:
    // in Custom0
    protected Context provideComponentContext( final Context parent )
            throws Exception
    {
        DefaultContext context = new DefaultContext( parent );
        context.put( "foo", "bar" );
        context.makeReadOnly();
        return context;
    }

then in Custom1 we want to override this:
    // in Custom1
    protected Context provideComponentContext( final Context parent )
            throws Exception
    {
        DefaultContext context = DefaultContext( parent );
        context.put( "blah", "blah" );
        context.makeReadOnly();
        return context;
    }

The thing I do not like about this is that the
hierarchies may get quite deep. I would personally
prefer
    // in Custom1
    protected Context provideComponentContext( final Context parent )
            throws Exception
    {
        DefaultContext context;
        if ( parent instanceof DefaultContext )
        {
            context = (DefaultContext) parent ;
        }
        else
        {
            context = new DefaultContext( parent );
        }
        context.put( "blah", "blah" );
        return context;
    }

and there is only one reason why this can not be done now:
by the moment Custom1.provideComponentContext gets 'parent'
it has already been made read-only.

The solution is not to make it read-only in

    custom0.provideComponentContext()

But when to make it read only then?

My answer is: at the very top, in AbstractContainer.
But we may do that only if we know what exact type
has been returned to us, _or_ if the object returned
implements a special interface providing such method.

We already know that there is Keel framework based on
Avalon that surely provides its own ServiceManager
to child components, KeelServiceManager. It is easy
to imagine that Keel's container will be subclassed
further in applications of Keel framework. So the
hierarchies I have described are not only quite
feasible but even likely to appear.

Then, I beleive that this is a sufficiently general
problem: pattern FactoryMethod is extremely widely
used (and this is what I address). And I beleive
that it will be a common desire (getting back to
our example) not to replace the code in

    super.provideComponentContext()

blindly overriding parent's implementation, but
to get something that parent has created and
slightly modify it. See Fortress

    initializeServiceManager() in
    ContextManager.java

for another example. Users won't be able to
completely replace it (or they will have to replicate
all the code from our implementation which will
be a bad idea from the maintenance point of view).

And it may be impractical
to chain serverl DefaultServiceManagers one on
top another only to override one or two entries.

_If_ the WriteProtectable interface will be introduced
(as I propose) then an overriden implementation of any
factory method will be able to call the parent's
implementation and provided it knows precisely what
type of object the parent generates it will be able to
modify _that_ object without wrapping it.


I beleive this may be a common enough applicaiton
of "Factory Method" patter. Shall we call it
"Augmented Factory Method"? ;-)


To rely on the type of object returned from parent
is still better then to copy and paste code from
parent. And even if this knowledge falls out of
date, the overriden implementation of factory
method may always fall back to the "good old"
wrapping strategy _if_ the runtime type check fails
(like in my examples).

NH> Is there a "time"/"sequence" constraint on when
NH> a WriteProtectable turns into a ReadOnly?
err..., now _I_ may be the one who does not understand :-)
I would reply to this that WriteProtectable never changes
into a ReadOnly as only one of these interfaces may
be implemented by a particular object, but I must have
misunderstood the question. The invoker of the factory
method descides when to make the object returned
from the factory method readOnly.

The reason I'm introducing ReadOnly at the same time
as WriteProtectable is that I want an XXXUtil.makeReadOnly
method to function like this:

if ( obj instanceof WriteProtectable ) { ... .makeReadOnly() }
else if ( obj instance of ReadOnly ) { /*do nothing*/ }
else { throw new IllegalArgumentException( "neither WP nor RO" ); }

the reason to want this is to enforce security.
Unless an object has provided a method to make it readonly
(implements WriteProtecteable)
or has been marked as being ReadOnly by nature
(FortressServiceManager - we can only read data from
it, not write)
then this object _may_ be read-write - the author of
this object just did not care about this.
Hence we do not want this object, it's insecure, we
want to blow up.

NH> You mention that it would be used on ServiceManagers, but if the 
NH> ServiceManager user does not need to know, then it is an implementation 
NH> detail and irrelevant to Framework.
I hope that my examples above have shown that althoug
users by no means have to know if their ServiceManager is
WriteProtectable or ReadOnly or anything, the
fortress/impl/AbstractContainer should be empowered
to make the objects created by its factory methods
read-only.

Also, I beleive that these classes will have an
application in user-space too. As I mentioned, what
I'm trying to do is to "augment" the "factory method"
pattern with an ability to modify the object created
by the implementation that is being overriden. I think
that it is equally suitable both for the container
internals and for client components (which too will
have factory methods and overriden implementations
thereof).

NH> Maybe I missed something important...
That's what we're here to -- to talk, to communicate,
it's my pleasure, let's do it!
Will be glad to answer further questions :-)

WBR, Anton


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Mime
View raw message