You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@avalon.apache.org by Stephen McConnell <mc...@apache.org> on 2003/10/04 18:32:55 UTC
Re: [RT] avalon (merlin) == safe == programmer effort
Leo Simons wrote:
> hammett wrote:
>
>>> (as opposed to the conceptually very clean avalon-style
>>> configuration where a component is allowed to "read" from its
>>> configuration, but the configuration itself is passive),
>>
>>
>> Biased! Biased! :-p
>
>
> ROTFL! Me? Nah..... ;)
>
> Seriously, one could only consider it conceptually very clean, don't
> you think?
>
> The avalon picture
> ------------------
> - a container is responsible for finding/creating the configuration
> according to preset rules (delegating this responsibility to a
> specialized component of course), usually allowing for various people
> in various roles (end users, assemblers, component writers) to follow
> various contracts to define the configuration,
>
> - a configuration object is then responsible only for existing
> (implementing the Configuration interface)
>
> - a component is responsible for obeying the directives provided to it
> by the container in the form of the configuration it receives (and
> complaining if it doesn't know how).
>
> Clean. Add in some more enforcable rules (like requiring component
> authors to provide a container-verifiable schema for the configuration
> format (like a DTD for XML) and component configurators to follow that
> schema), and, save for bugs, all behaviour is completely
> deterministic. Clean, safe, sound, understandable.
>
> The downside? In practice, especially with java and xml, it means way
> many lines of code to write.
Is this really the case? If a container does not provide the clean,
safe, sound and understandable context then your simply transferring the
responsibility to the component implementation to clean-up its act,
practice safe sex, demonstrate soundness of judgement, while maintaining
understandable code.
Given a scenario of one container, 1,000 component developers, and a
conservative 20 components per developer ... now let's imaging that each
developer writes 10 amazingly efficient lines of code in order to
facilitate responsible component semantics relative to the safe-sex
viewpoint. This means that we have a total 10x20x1000 lines of code
dealing with safe-sex from a number of different positions. That's
200,000 lines of code - and we only dealing with one viewpoint!
The alternative is to push safe-sex handling over to the container.
Let's assume that a container deals with this with perhaps 200 lines of
code (taking into account a broad spectrum of positional variations).
What we have is three order of magnitude improvement in the efficiency
and maintainability relative to the problems space.
>
>
> Note: its perfectly possible to write a very dynamic scripted
> avalon-framework container. It just happens to be the case that avalon
> (especially with Merlin) is moving further and further into the sound
> and safe, predictable and verifiable corner. In fact, some people
> (like Steve) assert that a container which is not predictable is a Bad
> Thing(tm). Me, I strongly disagree with that assertion :D
>
>
> The scripted picture
> --------------------
> - a container will look for a configuration script according to preset
> rules and run it according to some more rules
>
> - a configuration script had better exist and follow the rules
>
> - a component is not required to do anything special
>
> You lift some responsibility from the component and from the container
> at the price of requiring the end user to write a sensible
> configuration script or suffer the consequences.
>
> The upside? Every piece in this system is a lot simpler, and usually
> you end up with less lines of code everywhere.
>
> The balance
> -----------
> You have a few axes that are not orthogonal:
>
> clean <---------------------------> dirty
> safe <---------------------------> unsafe
> complex <---------------------------> simple
> static <---------------------------> flexible
> much effort <---------------------------> little effort
>
> Sacrifice some conceptual cleanness and predictability and you end up
> with a system that is both simpler and more flexible, and, most
> importantly, requires less typing.
Just so I understand the arguments here ... what you saying is that we
have this dirty little unsafe container. And, the principal redeeming
quality is the attribute of an absence of thought - woops, sorry - effort.
Ok, I'm hooked, let's go with the flow ;-)
>
>
> Choice
> ------
> In a banking application, you had better make sure that a
> misconfiguration does not ever result in anything bad happening. I
> wouldn't want scriptable ATMs. In your average web server, its okay if
> a web page decides to topple over every now and then, as long as it is
> easily and quickly fixed.
BZZZZT (private joke)
Doesn't work in a COP scenario. You don't know in what context your
component will be deployed - and without some notion of "quality of
environment", your strategy destroys the potential for component reuse.
Sure, if you have a bunch of dirty little components with all of the
benefits of street-smart wits, running in a dirty little container,
sure, you have economies of scale. On the other-hand, maybe I'm missing
the point ... but ... could you explain to me again why this is a good
thing?
:-)
Cheers, Steve.
(a dirty little developer brought up in a dirty big container)
--
Stephen J. McConnell
mailto:mcconnell@apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org
Re: [RT] avalon (merlin) == safe == programmer effort
Posted by Alexis Agahi <al...@users.sf.net>.
On Sunday 05 October 2003 13:32, Leo Simons wrote:
> The point is in seeing that back when we all (as IT community) chose
> XML, it was in some places a very bad choice :D
sure, XML is not designed for programatic stuffs (well maybe it depends on our
background, because I've seen incredible XSLT programming stuff, done by
people who had never seen anything like java).
> I'm not saying avalon's XML configuration mechanism should go. That
> would horrify everyone. I'm saying that, if you feel like replacing the
> de-facto standard of using XML with anything else (like the Jini 2.0
> config format we started this topic with), a scripting language like
> BeanShell or ruby is a better choice than anything else.
Ok, why not.
But sometime more choice equals more confusion. It is currently a bit hard to
explain the configuration IoC principle to devlopper, if you add scripting,
this could drive them to confusion and heterogeneity.
But I aggree that for quick dev/test phase this could help.
> But you'll have a hard time finding a seasoned sysop who prefers XML
> configuration to the Apache HTTPD config file (which is basically a
> custom scripting language), or the Samba one.
It depends.
If you consider "old style *nu|ix sysop" you are probably right.
> Its easy to find a java programmer who prefers an XML config file to a
> scripted one. But I just think all those people are being silly and I'm
> not :D
ok ;)
> > (even javascript is far from java).
>
> indeed. BeanShell has full support for java syntax. You could have java
> programmers write configurations in java (as per the examples I gave).
> You could have sysops write configurations in python or ruby.
yeahh. in your dreams ;) Most of the sysop (I'm not talking about sysop/hacker
profile) just want the application to run without having anything to do or
configure. Just take a look at how many IIS are running with default conf, to
see what I mean.
But ok, this does not mean that we should close all the doors.
> > Also XML is now well known for most of the sysop,
>
> I think its well-known to sysops who manage java applications. Outside
> that subset, I suspect most sysops don't know xml that well.
I'm not so sure.
> > XML config files are human readable,
>
> excuse me? Human-readable?
>
> http://cvs.apache.org/viewcvs.cgi/avalon/buildsystem/maven-common.xml?rev=1
>.9&content-type=text/vnd.viewcvs-markup
lol, ok.
easy shot. Do you want me to write you an url of unreadable sendmail config
file?
> barely. If I were to show my non-programmer flatmates your average
> tomcat config file as compared to your average apache httpd config file,
> I doubt any of them would go for the former.
The fact is that most of good programmers with the help of good frameworks
(;)) use to externalize *all* static value in config file. So this drives you
to huge conf file with 99% of value that you will never touch in most of the
time (take a look at jboss config).
For that, Merlin offers a good solution based on "defaut" .xconfig files for
each component, and help to reduce the main conf file (an increase
readability).
This is not a common practice in C/C++ *traditionnal* programming approch
(even if I guess that it is now more the case).
> in summary:
> "XML combines all the inefficiency of text-based formats with most of
> the unreadability of binary formats." -- Oren Tirosh, comp.lang.python
LOL
XML is just a self describing hierachical text format.
> > What could be done is having "Scriptable" components (such as
> > Initializable, or Configurable) that could be scripted during
> > component lifecycle.
>
> Hmmm. What would that interface look like? Something like:
> public interface Scriptable {}
>
> well, maybe a metadata tag would work better:
>
> /** @@Scriptable */
> public class MyBlah { /* ... */ }
>
> but, this metadata is also available by virtue of the script file being
> available. So strip that, too, and implement some simple logic like:
>
> if <<scriptfile exists for class>> // pseudocode
> try
> <<initialize using scriptfile>>
> catch
> <<issue warning>>
> <<initialize using avalon-framework>>
> else
> <<initialize using avalon-framework>>
>
> This, of course, leads to a lot of logic implemented in the container
> which is inflexible (if/elseif/elseif/else considered harmful). The fix
> is obvious: allow for a ComponentFactory/ComponentAdapter idiom (like
> fortress has, as does PicoContainer) and get more flexibility:
>
> factory = factories.select( class ) // pseudocode
> return factory.instance()
>
> class ScriptingFactory
> instance() return <<initialize using scriptfile>>
> class AvalonFactory
> instance() return <<initialize using avalon-framework>>
>
> class PolicyFactory
> instance()
> try
> return <<delegate to ScriptingFactory>>
> catch
> return <<delegate to AvalonFactory>>
As you wish. :)
All I've to say is that "scriptable" features could be nice (even if I'm not
really 100% convinced) for some applications, and could be availble as
lifecycle stage of the component.
> Implementation in merlin
> ------------------------
> I looked at that some time ago, and it is simply too much of a hassle.
> Merlin in its current form is simply not built with this kind of
> extensibility in mind. Which leads to the conclusion that, for the near
> future, probably no avalon container will be scriptable :D
ouch ;)
it is time to join the forces ;)
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org
RE: [RT] avalon (merlin) == safe == programmer effort
Posted by Leo Sutic <le...@inspireinfrastructure.com>.
> From: news [mailto:news@sea.gmane.org] On Behalf Of Leo Simons
>
> well, maybe a metadata tag would work better:
>
> /** @@Scriptable */
> public class MyBlah { /* ... */ }
I have though about things like:
public class MyComponent implements ... {
/** @@Configurable ("./@numThreads") */
private final int numThreads;
}
<component role="..." class="MyComponent" numThreads="15"/>
So you use an XPath expression to have the container set the field
values.
The problem is when you have configurations like the one the ECM uses,
where you're not just setting field = value, but have to iterate over
child
configurations and create objects based on them:
<component role="..." class="MyComponent">
<subcomponent class="..."/>
<subcomponent class="..."/>
...
</component>
Maybe:
public class MyComponent implements ... {
/** @@SubComponents ("subcomponent") */
private final Collection subComponents;
}
But the thing here is that we're moving into the "too much magic" land.
What if only one of the subcomponents should be created. Or what if a
special handler is desired? Of course, we could have the @@SubComponent
mean that a Collection not of the actual components but of a component
descriptor or factory should be created, but try to formalize that
contract
for compile-time safety...
/LS
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org
Re: [RT] avalon (merlin) == safe == programmer effort
Posted by Leo Simons <le...@apache.org>.
"We can't lose XML!"
--------------------
Alexis Agahi wrote:
> I dont think having scripting configuration should override current XML config
> model.
indeed. You point out how XML has been ingrained into daily life of
programmer and sysop. Its neither straightforward nor desirable to move
away from XML.
> <disclaimer>I'm not sure to understand exactly your point</disclaimer>
The point is in seeing that back when we all (as IT community) chose
XML, it was in some places a very bad choice :D
I'm not saying avalon's XML configuration mechanism should go. That
would horrify everyone. I'm saying that, if you feel like replacing the
de-facto standard of using XML with anything else (like the Jini 2.0
config format we started this topic with), a scripting language like
BeanShell or ruby is a better choice than anything else.
For the sake of argument...
---------------------------
Just for fun, let me play advocate of the devil some more....
> Having script means knowing another language
that all depends on what "another language", and to "whom" it will be
"another". You are right, of course, that many programmers and sysops
know XML.
But you'll have a hard time finding a seasoned sysop who prefers XML
configuration to the Apache HTTPD config file (which is basically a
custom scripting language), or the Samba one.
Its easy to find a java programmer who prefers an XML config file to a
scripted one. But I just think all those people are being silly and I'm
not :D
> (even javascript is far from java).
indeed. BeanShell has full support for java syntax. You could have java
programmers write configurations in java (as per the examples I gave).
You could have sysops write configurations in python or ruby.
> Also XML is now well known for most of the sysop,
I think its well-known to sysops who manage java applications. Outside
that subset, I suspect most sysops don't know xml that well.
> and proposing them
> "exotic" config file could fear them.
indeed. However, providing the choice of a format that is otherwise
quite a bit more familiar to them (RPM, for example, uses python scripts
for configuration) than xml might give some interesting results :D
Also, I place much more trust in sysops
> XML config files are human readable,
excuse me? Human-readable?
http://cvs.apache.org/viewcvs.cgi/avalon/buildsystem/maven-common.xml?rev=1.9&content-type=text/vnd.viewcvs-markup
barely. If I were to show my non-programmer flatmates your average
tomcat config file as compared to your average apache httpd config file,
I doubt any of them would go for the former.
> and application friendly (I mean you could have for exemple a main
> application that could generate XML config for all your running apps).
This is a /really/ great feature of XML. Had XML not bean
machine-readable, it would have never gotten anywhere. It requires about
a megabyte of jar files and a complex and heavy beast called xerces
(roughly as complex as, say, GCC) to implement, but yes, it can be
parsed by machines.
Scripting languages like python and ruby go *way* further than that
though. They provide built-in serialization/deserialization of any object.
Go further with something like YAML [1], and you can
serialize/deserialize just about any object into a format that is way
more human-readable than the most beautiful XML.
in summary:
"XML combines all the inefficiency of text-based formats with most of
the unreadability of binary formats." -- Oren Tirosh, comp.lang.python
Implementation in a container
-----------------------------
> What could be done is having "Scriptable" components (such as
> Initializable, or Configurable) that could be scripted during
> component lifecycle.
Hmmm. What would that interface look like? Something like:
public interface Scriptable {}
well, maybe a metadata tag would work better:
/** @@Scriptable */
public class MyBlah { /* ... */ }
but, this metadata is also available by virtue of the script file being
available. So strip that, too, and implement some simple logic like:
if <<scriptfile exists for class>> // pseudocode
try
<<initialize using scriptfile>>
catch
<<issue warning>>
<<initialize using avalon-framework>>
else
<<initialize using avalon-framework>>
This, of course, leads to a lot of logic implemented in the container
which is inflexible (if/elseif/elseif/else considered harmful). The fix
is obvious: allow for a ComponentFactory/ComponentAdapter idiom (like
fortress has, as does PicoContainer) and get more flexibility:
factory = factories.select( class ) // pseudocode
return factory.instance()
class ScriptingFactory
instance() return <<initialize using scriptfile>>
class AvalonFactory
instance() return <<initialize using avalon-framework>>
class PolicyFactory
instance()
try
return <<delegate to ScriptingFactory>>
catch
return <<delegate to AvalonFactory>>
Implementation in merlin
------------------------
I looked at that some time ago, and it is simply too much of a hassle.
Merlin in its current form is simply not built with this kind of
extensibility in mind. Which leads to the conclusion that, for the near
future, probably no avalon container will be scriptable :D
cheers!
- Leo
[1] - http://www.yaml.org/
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org
Re: [RT] avalon (merlin) == safe == programmer effort
Posted by Alexis Agahi <al...@users.sf.net>.
Leo,
I dont think having scripting configuration should override current XML config
model.
<disclaimer>I'm not sure to understand exactly your point</disclaimer>
Having script means knowing another language (even javascript is far from
java). Also XML is now well known for most of the sysop, and proposing them
"exotic" config file could fear them. XML config files are human readable,
and application friendly (I mean you could have for exemple a main
application that could generate XML config for all your running apps).
What could be done is having "Scriptable" components (such as Initializable,
or Configurable) that could be scripted during component lifecycle.
Cheers
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org
Re: [RT] avalon (merlin) == safe == programmer effort
Posted by hammett <ha...@apache.org>.
> MyBlah.configurator.strict.bsh
> ------------------------------------------------------------------------
> import org.apache.avalon.framework.configuration.Configurator;
> import com.blah.MyBlah;
>
> public class MyBlahConfigurator implements Configurator
> {
> public void configure( Object component )
> {
> assert component instanceof MyBlah :
> "component must be instance of MyBlah!";
>
> MyBlah blah = (MyBlah)component;
> component.setNumberOfThreads( 15 );
> }
> }
What's the difference? In order to perform configuration from Script
languages or a subset of java, the user will face a simple choice. We can
try for hours imagine if its human readable, if sysops will not suffer a
heart attack, but the actual decision is from users - who actually knows the
best for them.
I'd like to point out why Jini works the way it is. A server application,
which exports one or more services usually will have to choose a exporting
strategy, a simple proxy, RMI, or whatever exists or will be invented. So
this config file returns the exactly implementation of the desired Exporter
selected at runtime for that particulary environment. What? Are you saying
that this can be done through XML?
<component>
<exporter type="RMI" />
</component>
Ok, that's valid. So a component needs to know every type of exporting
possibilities and know how to configure each of them.
What?
<component>
<exporter class="net.jini.exporters.BasicExporter" />
</component>
Oh! That's better. And how the BasicExporter should be initiallized? It has
a important constructor, you know.
So now you see what they tried to solve :-)
Leo, you can shoot me now! :-P
Regards,
hammett
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org
Re: [RT] avalon (merlin) == safe == programmer effort
Posted by Leo Simons <le...@apache.org>.
Stephen McConnell wrote:
> BZZZZT (private joke)
:D:D
> On the other-hand, maybe I'm missing the point ...
that seems to be the case. It'll probably be difficult to get it across
though. Lets try a different approach....
Abstract
========================================================================
Scripting languages have an ideal syntax for configuration
files. They are *way* cleaner and simpler than XML, making
things simpler for the user. They are *way* more 'natural'
than any other solution, making things simpler for the
component author. They are easier to support in a container
than XML.
A scripting language like BeanShell can 'pretend' to be java,
allowing all the type safety features in java development
tools to kick in.
The downside with scripts might be that they are usually
active rather than passive, and that can be a security risk.
Though standard java security management can be used to avoid
those risks.
My earlier e-mail was mostly about the worries you have
when you take the next step after a scriptable configuration:
a scriptable lifecycle (or even scriptable everything).
Avalon-style Configuration
========================================================================
Configuration, avalon-style, is essentially the capturing of the
component-intrinsic variants of a component (as opposed to its
invariants or the container-intrinsic variants) into a generic value
object. This value object is created by end users, typically using xml,
according to a specification provided by the component author (ideally
an xml schema, often some javadoc examples), and provided to the
component by the container during the component startup phase.
Configuration validation would ideally be part of the container's
featureset, however, currently, most containers don't do configuration
validation and such validation is, in practice, left up to the
components. Also, in practice, xml-based configuration validation can be
very hard; xml simply isn't built for programming. Example:
MyBlah.xconf
--------------------------------------------------------------fragment--
<config>
<numberOfThreads>15</numberOfThreads>
<!-- ... -->
</config>
MyBlah.xconf.wrong
--------------------------------------------------------------fragment--
<config>
<numberOfThreads>fifteen</numberOfThreads>
<!-- ... -->
</config>
MyBlah.xconf.wrong2
--------------------------------------------------------------fragment--
<config>
<numberOfThreads>101</numberOfThreads>
<!-- ... -->
</config>
MyBlah.xconf.wrong3
--------------------------------------------------------------fragment--
<config>
<numberOfThread>20</numberOfThread>
<!-- ... -->
</config>
MyBlah.java
------------------------------------------------------------------------
import org.apache.avalon.framework.configuration.*;
package com.blah;
public class MyBlah implements Blah, Configurable
{
private int m_threads;
public void configure( Configuration config )
throws ConfigurationException
{
setNumberOfThreads(
config.getChild("numberOfThreads").getValueAsInteger() );
// will fail
}
public void setNumberOfThreads( int threads )
{
assert threads > 0 : "number of threads must be bigger than 1";
assert threads < 100 :
"number of threads must be smaller than 100";
m_threads = threads;
}
}
Fail-safe components thus do something like
--------------------------------------------------------------fragment--
public void configure( Configuration config )
{
int numberofthreads;
try
{
numberofthreads =
config.getChild("threads").getValueAsInteger();
}
catch( ConfigurationException ce )
{
numberofthreads = DEFAULT_NUMBER_OF_THREADS;
getLog().warn(
"An error occured parsing the configuration: unable figure out"
+ " the number of threads; proceeding with the default value: "
+ DEFAULT_NUMBER_OF_THREADS, ce );
}
setNumberOfThreads( numberofthreads );
}
public final static int DEFAULT_NUMBER_OF_THREADS = 15;
------------------------------------------------------------------------
There is quite a bit of argument verification (a try/catch clause,
provision of default values on failure, two assertions) in addition to
requiring the component author to deal with conversion from a generic
configuration interface into the component-specific information.
Any of the failures in the config files above will only be detected at
runtime (unless the component author provides a DTD and the user has an
editor that checks against that DTD *and* takes the time to configure
the tool to use the DTD). An error message might look like (in the case
of a good component writer and a good container):
container.log
--------------------------------------------------------------fragment--
ERROR - MyBlah - An error occured parsing the configuration: unable
figure out the number of threads; proceeding with the default
value: 15
A configuration error occured on line 2 of MyBlah.xconf.wrong2:
<stack trace goes here/>
but in practice its usually not quite as neat.
Scripted-style configuration
========================================================================
Configuration, scripted, is essentially the capturing of the
component-intrinsic variants of a component (as opposed to its
invariants; often the container-intrinsic variants are subject to some
scripting somewhere as well) either into a component-specific value
object or directly into the component state. In both cases, the creation
of the value object or the setting of the state happens in a script.
The creation of the component-specific value object or the setting of
the component state is done by end users, typically using a scripting
language, according to a specification provided by the component author
(in the case of a component-specific value object, the specification is
encoded into the value object, in the case of component state, the
specification is encoded into the component its work interface).
Configuration validation would ideally built into an end user tool that
enforces appropriate contracts (in the case of configuration specified
as java code, an IDE works very well). In practice, that is only
feasible using beanshell in 'strict' mode; dominant in the field are
other scripting languages and a trial-and-error approach.
Consider the above MyBlah class as a POJO component which is scripted by
a beanshell script in 'strict' mode (that means only actual java syntax
is allowed, no beanshell-specific shortcuts):
MyBlah2.java
------------------------------------------------------------------------
package com.blah;
public class MyBlah implements Blah
{
public final static int DEFAULT_NUMBER_OF_THREADS = 15;
int numberofthreads = DEFAULT_NUMBER_OF_THREADS;
public void setNumberOfThreads( int threads )
{
assert threads > 0 : "number of threads must be bigger than 1";
assert threads < 100 :
"number of threads must be smaller than 100";
m_threads = threads;
}
}
MyBlah.configurator.strict.bsh
------------------------------------------------------------------------
import org.apache.avalon.framework.configuration.Configurator;
import com.blah.MyBlah;
public class MyBlahConfigurator implements Configurator
{
public void configure( Object component )
{
assert component instanceof MyBlah :
"component must be instance of MyBlah!";
MyBlah blah = (MyBlah)component;
component.setNumberOfThreads( 15 );
}
}
------------------------------------------------------------------------
trick your editor into believing ".bsh" files are similar java files,
but should not be compiled, and you have near-complete type safety. We
have just a little bit of error-checking left (three assertions), things
are /completely/ type-safe, and any stack traces in the event of an
error will likely provide a lot more clarity. The downside: your end
user is required to know a bit of java. The configuration file is more
than a bit complex (though, I would argue, not *that* much more complex
than xml).
So we put beanshell into its "enhanced" mode, move some of the code into
the container (the instanceof check, in particular; casts are not
neccessary in beanshell, and we do a `with(component)`), and you reduce
the above class definition to:
MyBlah.init.bsh (provided by end user)
------------------------------------------------------------------------
numberOfThreads = 15;
MyBlah.init.bsh.wrong (provided by end user)
------------------------------------------------------------------------
numberOfThreads = 150;
MyBlah.init.bsh.wrong2 (provided by end user)
------------------------------------------------------------------------
numberOfThread = 10;
MyBlah.init.default.bsh (provided by component developer)
------------------------------------------------------------------------
numberOfThreads = 15;
(yes, really, this can be a valid beanshell code snippet and I've got
proof-of-concept code that illustrates this). The downside here is that
there is currently no tool around which can ensure compile-time (let
alone editor-time, like you get in 'strict' mode) safety. But it sure as
hell is a lot cleaner, and because the format is so much simpler,
mistakes might not be so easily made.
An error message might look like:
container.log
--------------------------------------------------------------fragment--
ERROR - MyBlah - An error occured parsing configuration file
MyBlah.init.bsh.wrong on line 1: assertion failed: number of threads
must be smaller than 100. Proceeding with the default value: 15
<stack trace goes here/>
The configuration is a lot friendlier than using xml, any error message
can be just as friendly and just as specific, the container code that
handles all this can be just as simple, and, what's more, there is less
checking to do for the component author.
The security issue
========================================================================
The potential downside with scripts is that they are active, whereas
value objects are passive. Example:
MyBlah.init.bsh.trytohack (provided by end user)
------------------------------------------------------------pseudocode--
numberOfThreads = 15;
stop(); // attempt to stop the MyBlah component
dispose();
// wreak havoc
import com.blah.bank.AccountManager;
billGatesAccount = 12345;
myAccount = 54321;
AccountManager.transfer( 100000, billGatesAccount, myAccount );
------------------------------------------------------------------------
the solution here is to
- either implement a java security policy that denies a configuration
script the ability to do anything but configure its component, or, more
simple and more common, or
- to assume that whomever has capability of changing the configuration
can be trusted.
Giving up a little more safety
========================================================================
So what was I all on about with sacrificing safety and soundness for
flexibility and stuff? Well, the above just scripts configuration.
However, it can often be a good idea to just script the complete startup
sequence. The only thing you let the container do is the dependency
management and provision of an "execution context"; the component
instantation and initialization is all up to the script. So something like:
MyBlah.startup.bsh
------------------------------------------------------------pseudocode--
logger = context.getLogger()
workingDirectory = ContextUtil.getWorkingDirectory( context )
otherComponent = container.get( OtherComponent.ROLE )
component = MyBlah( logger, workingDirectory, otherComponent )
component.numberOfThreads = 15
component.initialize()
------------------------------------------------------------------------
you give up some safety here, because you are now depending on the
configuration script to properly handle the lifecycle startup contract
(in this case, the scripter might forget to call initialize(). What you
gain, of course, is flexibility: you can support any component lifecycle
with no extra container code or any kind of specification at all, by
virtue of allowing a component-developer-provided, possibly end-user
modified script to deal with it.
And you don't have to stop there. I'm currently experimenting with
exactly how much functionality to move into scripts. I'm working on
stuff which has the following in its Main class:
Main.java
--------------------------------------------------------------fragment--
public final static void main( String[] args ) throws Exception
{
Log log = null;
Server server = null;
try
{
Interpreter i = new Interpreter();
i.set( "args", args );
i.source( "startup.bsh" );
log = (Log)i.get( "log" );
server = (Server)i.get( "server" );
Now, /this/ is definately an approach where "startup.bsh" is pretty
elaborate and places a significant burden on its maintainer to make sure
it works.
Conclusion
========================================================================
Scripted configuration is definately worth a big BZZZZT! Its way
cleaner, cooler, faster, simpler, smarter and simply better than
xml-based configuration.
You can go further than scripted configuration and script large parts of
your application. Only *then* are you on slippery ground.
g'night!
- Leo
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org