Hi Leo:
Good to see your hard at work!
Some agreements and some disagreements in-line.
;-)
Leo Simons wrote:
Stephen McConnell wrote:
Only works if we cater for all of the requirements. I.e. the LCD approach fails the usability test.
it fails some tests, not all. A LCD is always less usable, but the point is that it is still usable. For example, in merlin, versions might default to 1.0.0 if left unspecified, names might default to lowercased classnames, @avalon.dependency mapped into @avalon.meta.dependency and @avalon.service mapped into @avalon.meta.service, resulting in a fully functional LCD.
LCD fails to deliver the aim of portable declarations.
If a component declares a lifecycle stage then that component should not be deployable in Phoenix. To ensure this - the Phoenix meta generation tool MUST recognize a lifecycle stage extension tag. Same story for lifestyle - it MUST be recognized in order to ensure non-deployment. LCD simply means potential runtime failure. This makes LCD unusable.
== @avalon.meta.namespace == class Enables client modification of the tag namespace.
<snip>
I aggree that this one can dissapear.
== @avalon.meta.version == class Identifies a class or interface are a Type or Service.
<type><info><version>1.3.0<version></info></type>
=== comments ===
- why is there a <version/> for classes?
It is the declaration of the implememtation version of the class. This reflects the behavioural contract (as distinct from the interface contract). A component with a major version incriment refects a incompatible semantic change which may be independent of the interface change. For example, semantics may be introduced on the interpritation of a string argument. The interface reamins the same, but the sematics of the implementation may have changed in an incompatible manner. This information can be used by custom selectors and/or management tools.
- can you depend on a version of a class? Why?
An ORB version 1.x is very different to version 2.x. The implementation version 2.1 a lower level of functionality to 2.4. Yes - you can depend on this sort of information because it reflects compliance with implementation semantic constraints.
- why is the standard '@version' tag not usable for this purpose?
The @version tag is typically used to reflect CVS versioning. Overloading this with formal class implementation versioning would be a bad thing to do.
== @avalon.meta.attribute == class A attribute associated with a containing type or service.
<service> <attributes> <attribute name="description" value="an example"/> <attribute name="color" value="red"/> <attribute name="priority" value="normal"/> </attributes> </service>
=== comments ===
Is it not better to simply make all unknown javadoc tags into an "attribute"? IE:
/**
* @my.tag jo!
* @my.second.tag blah blah blah
*/
I don't like the idea of bundliung anything that is unknown (I can just see lots of future problems, not to mention the fact that junk information will end up on the screens of management tools).
These attributes are used to suppliement a component description with information that will typically be specific to a container , component or service. In the general case - attributes should be ignorable - but there defintition as meta-info attributes should be explicit. This simply means that if a named value pair is to be associated with a component type - then there is a standard way to do it.
<snip-examples/>
I like the declaration approach of multi attributes ion a single declaration. The current approach was largely driven by the assumption that multiple line usage was not possible (thanks for the correction on that one).
As far as the type and service instance meta-info declaration is concerned this could be expressed as:
@avalon.info
somekey="some value"
anotherkey="another value"
More in general, javadoc tags are attributes already, so why specify a special kind of "attribute" to mark an attribute as an attribute? Similarly, <attribute/> feels icky, since an xml attribute is defined as
<element attributename="attributevalue"/>
Bacause explicit attribute declarations ensure the XML based meta-info can be validated against a DTD. This means that we have to deal with known attribute names and elements. The sort of attribute keys and values we are dealing with here are unknown.
== @avalon.meta.name == class Declaration of a component type name.
The name tag associates a name to a component type. The name tag is a required when generating a type descriptor.
=== Comments ===
That's a bit vague; the type DTD got me
<!-- The component element describes the component, it defines:
name the human readable name of component type. Must be a string containing alphanumeric characters, '.', '_' and starting with a letter. ... -->
I think "human-readable" implies a free form string. IIUC, name is used to hold a reference to a type, component, service, in map structures (ie HashMaps, service managers, etc), but that only requires uniqueness, not anything else.
If it is _not_ used for this, then what is it used for at all?
Within Merlin it provides two functions
(a) the association of a name to the type (e.g. "keystore") that
can be viewed by a management tool
(b) it establishes the default name for an implict deployment
instanceBoth name and version tags could be combined under a @avalon.component tag:
@avalon.component name="keystore" version="2.7"
== @avalon.meta.lifestyle == class Declaration of the lifestyle policy.
=== comments ===
the above sample provides ambiguity (example:
Agreed. This has already come up on the users list. The lifestyle attribute will be folded into a sub-element of the <info> block in the near futue.
== @avalon.meta.service == class Service export declaration from a type.
This maps to '@avalon.service' from AMTAGS directly:
Yep.
* @avalon.meta.service type="net.osm.vault.Vault; * @avalon.meta.service type="net.osm.vault.KeystoreHandler:2.1.1;
note the typo, this should be:
* @avalon.meta.service type="net.osm.vault.Vault"
* @avalon.meta.service type="net.osm.vault.KeystoreHandler:2.1.1"
Brain is on slow - what type?
=== comments ===
Of course, the ":2.1.1" is there for a reason. The example implies this is not a freeform string, but rather a specific version of a service may be exported by providing ":2.1.1". Especially since no prefix results in auto-addition of ":1.0.0". This seems like a bad idea. These things are seperate and introducing another kind of construct (the ':' within a value to seperate values) seems much worse than
* @avalon.meta.service type="net.osm.vault.Vault" version="1.1.1"
Moving to an explicit version would be implicit with migration to a complete "common model".
<type> <info> <version>5.1.0</version> <name>vault</name> </info> <services> <service type="net.osm.vault.Vault" version="1.1.1"/> </services> </type>
Better stil, since the code will do
class MyVault implements net.osm.vault.Vault
it is probably a better idea to have the tool determine what version of Vault is exported by taking a look at what version of Vault is on the compile path. That requires some work of course.
More than a little work when you take into consideration the possibility of multiple service defitions of the same type but with different versions. This possibility exists as soon as you have stacked repositories mapped to stacked classloaders.
== @avalon.meta.stage == class Lifecycle stage dependency declaration.
=== comments ===
this is container-specific. Or perhaps excalibur-lifecycle-specific.
It is not container specific.
It is a concept used in the majority of Avalon containers (Fortress and Merlin) and needs to be recognized by Phoenix because Phoenix needs to throw out componets that require extension stages. This is one of those "crunch" issues - if we don't recognize extensions we cannot deliver portable defintions.
== @avalon.meta.extension == class Lifecycle stage handling capability declaration.
=== comments ===
this is container-specific. Or perhaps excalibur-lifecycle-specific.
Unlike the stage declaration, this can be container specific because it is the defintion of a components ability to provide extension handling.
== @avalon.meta.logger == enableLogging() Logging channel name declaration.
/** * Supply of a logging channel to the component. * @param logger the logging channel * @avalon.meta.logger name="system" */ public void enableLogging( Logger logger ) { super.enableLogging( logger ); m_system = logger.getChildLogger( "system" ); }
<type> <info> <version>2.4.0</version> <name>component</name> </info> <loggers> <logger name="system"/> </loggers> </type>
=== comments ===
by contract, logger.getChildLogger() should work, even without such a declaration. So why is the declaration there at all?
The declaration is there so that assemblers can do useful things. You want to declare (via a directive) a logging target for a nameed channel. The only way you can do this from a management tool is to pull in the channels declarations that a type declares. For example, you may have a channel that you want to encrypt. How does the management tool get a refewrence to the channel name in order to build the directive?
In particular, what happens if you change to <logger name="blah"/>? Nothing, right?
Wrong.
What changes is the information that is presented to a management tool and the potential for assembly stage customization and control (i.e. what changes is the usability and manaagability of the component system).
== @avalon.meta.context == contextualize() Declaration of a specialized context class.
/** * @avalon.meta.context type="net.osm.CustomContext" */ public void contextualize( Context context ) throws ContextException { CustomContext custom = (CustomContext) context; ... }
=== commments ===
that should be discouraged! The contextualize() contract is that a component can expect to receive a Context, nothing /more/, nothing /less/. I think BlockContext shows how problematic the above is.
Avalon contextualize implies this constraint. In practive many containers define extended context interfaces (Phoenix, Plexus, ...). In addition users prefer to use things like File file = context.getWorkingDirectory() as opposed to File file = (File) context.get( SOME_KEY ). Thing is that this is required if you going to run a Phoneix component that assumes BlockContext. The important point here is that Avalon containers need to recognize this casting criteria and reject the component if they cannot support it.
I.e. this is one of those CRUNCH issues.
== @avalon.meta.entry == contextualize() Context entry declaration.
=== comments ===
thought for a bit how this might be combined with @avalon.meta.dependency. Probably not a good idea.
This is also one of those declarations that must be recognized. Optional entries can be ignored by containers, non-option cannot be ignored.
== @avalon.meta.dependency == service() Service type dependency declaration.
=== comments ===
maps to '@avalon.dependency' in AMTAGS.
Yep.
== More on versioning ==
Lots of unanswered questions.
- do you really need this granular versioning?
Yes.
Isn't versioning per deployable unit enough?
No. Different granularity.
- when is a service backwards compatible?
Backward compatibility is undefined at this time (i.e. versions are managed at absolutes). Looking forward, backward compatability semantics would require more work on things like the framework Version class.
How do you specify a version range?
Version ranges are not included.
- how are versions actually used in container space? What can you expect to happen when you declare a version?
Components in a hierachy can provide different versions of the same interface. When your mapping a provider to a consumer component you basically search up the tree for a component exporting a matching service (where matching means equivalent interface classname and equivalent version). As mentioned above - this matching algorith is currtently absolute but this is isolated in the equality test for a service reference (allowing more general version semantics in the future).
- how "optional" can version support be in a container?
A container can ignore this information and depend on "hope". The level of confidence you can assign to "hope" semantics is typically a container implemetation issue. Containers that use this information can provide assured solutions.
== summary ==
use of '@avalon.meta' is a bad idea. [EMAIL PROTECTED]/@merlin/ would be nice.
My biggest issue is with versioning. Either go all the way and declare (for example) that the arguments to some of the tags are urns in the avalon namespace (and declare the format for urns in that namespace), or be consistent in application of a pattern.
Also, I'm sceptical as to the need of this granular kind of versioning, especially with regard to implementations.
=== existing merlin tags ===
@avalon.meta.namespace should just dissapear
+1
@avalon.meta.version should just use '@version', if needed at all
-1 mixes different concerns
@avalon.meta.attribute should just dissapear; this stuff
is attributes already. If there's really a need for avalon container
support, just implement a generic algorithm that stores all unknown
attributes (or even all attributes), rather than invent a new
mechanism
-1 should not dissapear - tag spec and structure can be improved
@avalon.meta.name needs more specification as to intended usage, and perhaps should allow free-form strings
+1 on more specification -1 on free-form strings
@avalon.meta.lifestyle no comment
@avalon.meta.service <-> AMTAGS @avalon.service; concerns about versioning setup
@avalon.meta.stage tied to excalibur-lifecycle package
@avalon.meta.extension tied to excalibur-lifecycle package
@avalon.meta.logger should just dissapear
-1 Put on a suite, re-read email, and think about management implications.
@avalon.meta.context has a use case because there exist components that depend on specific context implementations or extensions (ie BlockContext), but should be discouraged
If you have a complete interoperable solution - then there is no need to discourage the practice. It is possible to provide solutions to both context casting and context semantic additions (and both are required if you want to provide complete Phoenix compatibility). All we should be addressing here is "what information at the tag level is needed to completely declare the criteria of a component type". Using Phoenix as a case study this means (a) context casting assumptions, (b) context enty assumptions, (c) context behavioural assumptions. Our tag model for context has to address all three.
@avalon.meta.entry no comment
@avalon.meta.dependency <-> AMTAGS @avalon.service; concerns about versioning setup
== conclusion ==
The tags currently in use by merlin are not ready for generalization into a "full suite of tags". I think some things do not make sense, and in other places contracts are underspecified.
I think you have made some good suggestions for improving the Merlin tag suite. I also think you still missing the point about what is really required for a generic and complete specification that would enable "assured component portability" and "assured component integrity". What I'm talking about is recognizing that a bunch of stuff MUST BE RECOGNIZED irrespective of container support. Until we reach a general acceptance of this truth a common tag model will be of little value.
Cheers, Steve.
--
Stephen J. McConnell mailto:[EMAIL PROTECTED] http://www.osm.net
Sent via James running under Merlin as an NT service. http://avalon.apache.org/sandbox/merlin
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
