Return-Path: Delivered-To: apmail-jakarta-avalon-dev-archive@apache.org Received: (qmail 9175 invoked from network); 12 Dec 2002 12:01:15 -0000 Received: from unknown (HELO nagoya.betaversion.org) (192.18.49.131) by daedalus.apache.org with SMTP; 12 Dec 2002 12:01:15 -0000 Received: (qmail 20225 invoked by uid 97); 12 Dec 2002 12:02:20 -0000 Delivered-To: qmlist-jakarta-archive-avalon-dev@jakarta.apache.org Received: (qmail 20158 invoked by uid 97); 12 Dec 2002 12:02:19 -0000 Mailing-List: contact avalon-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Avalon Developers List" Reply-To: "Avalon Developers List" Delivered-To: mailing list avalon-dev@jakarta.apache.org Received: (qmail 20143 invoked by uid 98); 12 Dec 2002 12:02:19 -0000 X-Antivirus: nagoya (v4218 created Aug 14 2002) Content-Type: text/plain; charset="iso-8859-1" From: Darrell DeBoer To: "Avalon Developers List" Subject: Re: [Avalon4:PROPOSAL] Context Consensus Date: Thu, 12 Dec 2002 22:03:37 +1000 User-Agent: KMail/1.4.3 References: <5.1.0.14.2.20021211001952.00bb1758@mail.sutic.nu> In-Reply-To: <5.1.0.14.2.20021211001952.00bb1758@mail.sutic.nu> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-Id: <200212122203.37915.darrell@apache.org> X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N G'day On Wed, 11 Dec 2002 09:23, Leo Sutic wrote: > NOTE REGARDING consensus: Darrell voiced opposition to this scheme. > However, it seemed to me that the objection was based on the assumption > that the container would have a dependency on T. Darrell, does your > objection still stand? I certainly don't plan to fight tooth and nail over it. However, I've yet to see any argument where the benefits of requiring a castable context outweigh the added complexity. So yep, I still feel the same way; I'd rather keep the context simple. > There is consensus that a method of specifying a context interface is > needed in order to specify the Phoenix BlockContext given its current usage > pattern. Only to make the current usage pattern concrete and required as part of the Avalon Framework contracts. There's no reason that we can't declare the current usage to be Phoenix-specific, keep it working in Phoenix, provide a better way, and *gently* encourage people to move over to it. ... > THE CAST-ABILITY OF THE CONTEXT INSTANCE .. snip .. > I don't think it is productive to assume that all code written for Phoenix > can be changed, no matter how small the change. Even if it would only take > one line of code: > > Change: BlockContext bc = (BlockContext) context; > To: BlockContext bc = (BlockContext) context.get > (BlockContext.CONTEXT_KEY); > > Multiply that with the number of places, and consider that the project > where this code exist not only depends on Phoenix, but on some 30-odd other > APIs that may change slightly, and you have a bunch of developers that do > nothing but continuously scan the code, making millions of "simple one-line > change[s]". > > Therefore I think that if attainable, the proposal must formally make the > Phoenix usage pattern valid. Not left as a container-specific extension, > but formally accepted, meaning that it can't be taken away without changes > in the stable Framework (as opposed to dropping support for a > container-specific extension). I understand your argument for not wanting to make what is common-usage into something that is container-specific. But I don't really agree. In for this "context-meta" stuff to work, developers are going to have to write code to upgrade their components. Something to describe their expected context entries. Until they do so, if they are casting the context, or retrieving a key, they are going to be operating in a container-specific manner. That's OK. But *when* they decide to upgrade to the *new* Context-Meta specification of the framework, wouldn't it be good to encourage them to take on a new, better usage pattern as well. * One that *can* automatically throw a ContextException if the requested entry isn't there. (casting can't) * One that allows Containers to support their request in a simple way, without proxies and tricky code, so it'll be easier to support in a resource limited environment (J2ME). * One that let's us add Context.has( String key ), so that "optional" entries can be easily tested for by the component author. (I guess "instanceof" would work for casting) BUT MOST IMPORTANTLY: *A usage pattern that allows us to have a single way of describing what's in the context, not 2 separate ways for entries and castable interfaces. These developers are going to be writing code to support context-meta. One more line change won't hurt. And if they don't do it, that's OK. The components just may not run in every container. > The purely practical aspect of this is best illustrated with a scenario: > Phoenix CVS has burnt up, and all developers had just wiped the Phoenix > source code from their drives (and of course no one has a backup). Thus, > all the ex-Phoenix developers have to migrate their projects to some other > container, and that *fast*. > > Say that they decide to move to Merlin. .. snip .. > The point of the above is that even if Merlin doesn't support Phoenix > emulation, adding such code can be done in the knowledge that it isn't a > hack, but has full support in Framework and can be done without introducing > any coupling to Phoenix. Why would "full support in Framework" be so important in such a (far-fetched) disaster scenario. Surely we'd just plug Merlin to work like Phoenix (like you suggested), but hopefully work out a way to give deprecation warnings. > > And that's why I'm pro-context-casting. And that's why I'm not. And I'm particularly impressed by the arguments *against* context-casting in the next section... :) > > THE PROPOSAL ITSELF (AS IT IS NOW) > > A context is defined by two sets of parameters. The first is an interface > or a class, called T below. If an interface, it is an interface that the > supplied context interface must be cast-able to. If it is a class, it is > expected that the class is instantiated with the T(Map,Context) > constructor, and that the instance is passed to the component's > contextualize method. This makes me feel a bit icky. It *feels* like implementation details impacting on framework design. I'd need a good explanation as to why this was required before I was convinced. I'm guessing that this is the way Merlin populates Context entries from it's "context providers" or whatever they are. (Not dissing, just not familiar enough). I've said before, I think this is probably a cool container design, but pluggable "context-providers" don't necessarily have to be container-portable, surely. Let's get clear, clean contracts that work for the bulk of components out there. You know, the one that the *users* of the framework are writing. The ones that access databases and filesystems and maybe need to ask the container to shutdown. Maybe later we can come up with an infinitely flexible Framework that allows us to implement portable lifecycle extensions and context providers. But I'd vote to do the easy stuff first, see how it works, and then move on to the harder stuff. > NOTE: In the case where T is an interface, the container must supply an > implementation for all methods in the interface. This may be done via a > dynamic proxy that routes calls to appropriate handlers or by any other > method. The set of methods that a container must support is defined by the > standard context interfaces in Framework (currently none). Doesn't this sound very complex, for the simple declaration of "what I want in my context"? To me, it looks like the sort of thing that we'd look back on and say "what on earth were we thinking?!?". Maybe I'm misunderstanding: You mean we let the Component author declare *any* interface (combination of different bits and pieces) as it's context requirements? So I need a getHomeDirectory() and a getShutdownRequestHandler() method, so I can just invent an interface with those 2? And the Container, if it wants to run my component, has to somehow come up with an implementation that can cast to that interface? Surely not? > > The second set of parameters are the entries accessible via the Context.get > method and their types. The class/interface T above may have associated > metadata that specifies entries. These entries must be supplied by the > container in addition to any entries the component itself requires. > > Each entry requirement must specify the canonical key name, may specify a > name that the canonical key should be remapped to, and must specify the > expected type of the value: > > For an example, where the data is specified in XML: > > > > > Ahhh. Now this all feels more real. I want a java.io.File called "avalon:work" in my context. Yep, makes sense. Let's say I expect a java.sql.DatabaseMetaData (interface) in my context. I'd ask for it to be an *entry* in my context. It would crazy for me to suggest that the container should provide me with a context that I can cast to java.sql.DatabaseMetaData. So why should it be different for BlockContext? Putting aside the fact that that's how Phoenix works today. If that's the *only* argument for it, then let's be honest and say so; if most people then agree that it's valid, then fair enough. Sorry to be difficult, but this is just my feelings on the matter. Then again, since no-one else seems to be objecting, maybe I'm the odd one out here? -- cheers, Darrell DeBoer -- To unsubscribe, e-mail: For additional commands, e-mail: