cleaned up demo scripts locations
[urisagit/Stem.git] / Design / config_notes
CommitLineData
4536f655 1
2 Stem Object and Cell Creation and Configuration Design Notes
3
4All Stem cells and objects share the same API style in their constructor
5methods (commonly 'new'). All parameters are passed as key/value
6attributes and processed with Stem::Class::parse_args which is driven
7with a simple table of field descriptions. Each field is described by an
8anonymous hash with attribute/values. Each allowed field must have a
9name and it also can have several optional description attributes. Here
10are the supported field description attributes:
11
12 name The value of this is the name of this
13 field. Obviously the field name is required.
14
15 required This is a boolean value that says this field
16 is required. If it is not set in the constructor
17 call, an error string is returned.
18
19 default The value for this is the default for this
20 field. It is used if this field is not set in
21 the constructor.
22
23 class The value for this is a Stem class (Perl
24 package) name. It means the value of this
25 parameter will be parsed as the arguments to the
26 constructor ('new' for now) of that class. The
27 object returned is saved as the value of this
28 field. If the called constructor returns an
29 error string, it is returned.
30
31 class_args The value of this is an anonymous list
32 of attribute/value pairs for this class
33 field. They are passed after the caller's
34 arguments and so will override any duplicate
35 passed in parameters.
36
37 callback The value of this is a code reference which is
38 called to do custom construction of this
39 field. The code ref is called with the new
40 object, the field name and the anonymous
41 reference which has the field's passed in
42 values.
43
44 type The value for this attribute is the type of the
45 field. Currently unsupported, it is meant for
46 stronger type checking of parameters such as
47 booleans. This will be supported soon.
48
49 env The value for this attribute is a name of a Stem
50 environment variable. If this name is found in
51 %Stem::Vars::Env then the value in that
52 hash is used as the value for this
53 attribute. This overrides any value passed in
54 the the constructor or a default option.
55 NOTE: Stem environment variables can be set from
56 many places including the command line, the
57 shell environment, command messages and the terminal.
58
59Here is a typical constructor from the Stem::Log class. It has 3 fields
60of which the first is required the other two have defaults. The
61beginning of the constructor sub is shown below and that same two lines
62of code is used in almost every class constructor.
63
64
65my $field_info = [
66
67 {
68 'name' => 'log',
69 'required' => 1,
70 },
71 {
72 'name' => 'level',
73 'default' => 'info',
74 },
75 {
76 'name' => 'text',
77 'default' => '',
78 },
79
80] ;
81
82sub new
83
84 my $self = Stem::Class::parse_args( $field_info, @_ ) ;
85 return $self unless ref $self ;
86
87
88Object Creation Error Handling
89
90Stem cells and objects are being created all the time and in many
91ways. There is a standard way Stem constructor subs return errors. If the
92object construction works, it returns the object. If there is an error,
93it returns the error string. The caller must test constructor
94returns with ref to see if they worked. This makes it easy to pass back
95error messages to higher level objects with this code shown above.
96
97The first line parses the passed arguments (in @_) with a field
98description table. The second line tests if an object was created. If it
99was (ref $self is true), then the constructor continues. Otherwise, the
100error string is just returned to the caller. So the exact low level
101error is propagated up the call tree. This is used consistently in all
102of the constructors so even if you have a class which has a field which
103is a class (see the 'class' field type above), and it has a parse error,
104that error will be passed all the way up to the highest level call
105(typically in the Stem::Config module).
106
107Stem Cell Configuration
108
109Stem cells are typically created by the Stem::Conf class. The primary
110source of configuration data is from a file and that is handled by the
111load method. Currently config files are legal Perl and are just parsed
112with string eval. (Don't yell, I know it sucks but it is simple to
113bootstrap.) The next revision of this module will tighten up the
114specifications of config files and create a proper parser for it. The
115parser will probably use Parse::RecDescent (written by our advisor
116Damian Conway who will probably write the parser for us :). The config
117syntax will probably be similar to what it is now, but barewords
118(actually any token without whitespace) will be allowed anywhere. Only
119value strings with white space will need to be quoted. Config keywords will
120always be barewords. Fat comma will be supported and [] will demark
121lists of anything. There won't be any hashes since this is really just a
122mass of initializations and a list is fine to initialize a hash.
123
124A Stem cell configuration is comprised of a list of attribute/value
125pairs. You can also have a list of cell configurations in one file,
126but each configuration is handled independently. Each configuration
127entry has only a few options in the usual format of key/value pairs. The
128first is 'class', which is required and it names the Stem class which
129will be configured. The next one is 'name' and it is optional but almost
130always used. It is the name that this cell will be registered as and
131that is the address that will be used to send messages to this cell. The
132last major option is 'args' and its value is a list of attribute/value
133pairs used to initialize the cell. Which set of configuration options
134is what controls how a cell is created and/or registered.
135
136The 'class' option is first processed and if it is not loaded, Stem will
137load it for you. This can be done remotely which allows for a servlet
138style of behavior, i.e. a request can come in and be a configuration or
139converted to one and the required Stem class will be loaded and a cell
140created. That cell can then be passed a message and respond to it. All
141of that can occur at runtime on demand.
142
143If the 'args' option is set, then a constructor of the class is called
144and it is passed the attribute/value pairs from the list value of
145'args'. The constructor method is defaulted to 'new' but that can be
146overridden with the 'method' option. The constructor processes its
147arguments (most likely using the Stem::Class::parse_args routine
148described above) and has 3 possible return values. If it returns undef,
149nothing more is done by the Stem::Conf module for this configuration. If
150a string is returned, that is assumed to be an error message and it is
151either printed or returned to the originator of this configuration. Any
152other configurations in this file (or passed in remote configuration)
153are skipped. If the retun value is a ref, then it is assumed
154to be an object and it can be registered with the address in the 'name'
155option.
156
157If the 'name' option is set, that will be used to register the cell or
158class itself. In most of the configuration cases, an object is created
159by the class constructor with the 'args' option and it is then
160registered as a cell with that name for its address. If no 'args'
161option is set, then the class itself is registered under the 'name'
162value and it is a class level cell. There can only be one class level
163cell for any class although it could be registered under multiple names
164(aliases). In addition, the value of the 'name' option is passed along
165with the 'args' values to the constructor as the attribute 'reg_name'.
166
167Here are some example classes which are configured in several of those
168ways:
169
170The Stem::Hub class needs to be initialized with a registration name
171but has no other attributes. So its configuration has a 'name' and an
172'args' option whose value is an empty list (that forces the constructor
173to be called).
174
175 [
176 class => 'Stem::Hub',
177 name => 'server',
178 args => [],
179 ]
180
181The Stem::TTY::Msg class configuration doesn't use the 'name' option and
182it used an empty 'args' value. So its constructor is called and it
183returns its single class level object, and that is registered under its
184class name.
185
186 [
187 class => 'Stem::TTY::Msg',
188 args => [],
189 ]
190
191
192The Stem::Demo::Cmd class is a class level cell that just has a 'name'
193option in its configuration and that is used to register the class
194itself.
195
196 [
197 class => 'Stem::Demo::Cmd',
198 name => 'cmd',
199 ]
200
201
202The Stem::Sock::Msg is configured in the most common way, with 'name' and
203'args' options and values for the arguments.
204
205 [
206 class => 'Stem::Sock::Msg',
207 name => 'C',
208 args => [
209 port => 6668,
210 server => 1,
211 data_msg => [
212 to_cell => 'sw',
213 to_target => 'c',
214 ],
215 ],
216 ]
217
218
219Normally a single configuration file is loaded by the run_stem program
220at start up time. The Stem::Conf module also supports loading a
221configuration file via a command message or another configuration (which
222is similar to include files or Perl modules). A configuration which
223loads a configuration file can evaluate in the current Hub or send it to
224any Hub in the Stem system. This allows for centralized management of
225Stem configurations. As an aid to this, the stem_msg program can be used
226to send a 'load' command message to a Hub.
227