summaryrefslogtreecommitdiff
path: root/fml/doc/en/tutorial/module/IO.sgml
blob: ed326efbe17dba202477b89fa53dbb5617a1a93b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
<!--
   $FML: IO.sgml,v 1.2 2003/08/03 01:47:17 fukachan Exp $
   $jaFML: IO.sgml,v 1.4 2003/04/15 14:51:42 fukachan Exp $
-->

<chapter id="module.io.adapter">
	<title>
	IO Abstraction Layer (IO::Adapter Class)
	</title>


<sect1 id="module.io.adapter.overview">
	<title>
	IO::Adapter Overview
	</title>

<para>
All IO of &fmldevel; should use IO::Adapter class like vfs/vnode
framework. For example, read/write member list, add/remove a user.
The usage is like this:
<screen>
use IO::Adapter;
$obj = new IO::Adapter $map, $map_params;
$obj->open || croak("cannot open $map");
while ($x = $obj->get_next_key()) { ... }
$obj->close;
</screen>
</para>

<para>
$map is map:identifier. file: can be omitted.
Currently available maps follow:
<screen>
file:/var/spool/ml/elena/recipients
unix.group:root
nis.group:root
mysql:id
postgresql:id
ldap:id      
</screen>
</para>

<para>
"file:" map is a normal file (text file).
"unix.group:root" map is to read root entry in /etc/group file.
"nis.group:root" map is to read root entry in NIS (YP).
"mysql:id" map implies the use of MySQL.
Parameters for MySQL access is defined in "mysql:id" entry.
These paraemeters should be specified before calling "new
IO::Adapter".
</para>

</sect1>


<sect1 id="module.io.adapter.methods">
	<title>
	IO::Adapter Methods
	</title>

<para>
Official methods IO::Adapter provides currently follow:
<screen>
new()
open()
close()

get_next_key()

add(KEY)
delete(KEY)

getpos()
setpos(NUM)
eof()

touch()

find(REGEXP, $args)
</screen>
</para>

<para>
KEY is a primary key to handle database access. In almost cases, the
primary key is a mail address. REGEXP is a regular expression
(regexp), this is usually also a mail address.
</para>

<para>
Unification of all types of IO needs that we should implement least
methods.
</para>

<para>
The currently implemented methods are selected by test and our
operations. If could, we refer SQL IO more than file IO as an
abstraction base model of IO::Adapter. It introduces difference
between &fml4; and &fml8; but it is mandatory for further abstraction.
</para>

</sect1>


<sect1>
	<title>
	Argument Type Of Methods
	</title>

<para>
The argument needs nothing, STR or ARRAY_REF as the argument and the
return value is STR. get_next_key() is typical as the no argument
case. This method is used to list up the content of files or retrieve
the specific address in the file.
</para>

<para>
In other case, the return value may be a pair of strings.
<screen>
KEY_STR => [
     VALUE_STR_1
     VALUE_STR_2
     VALUE_STR_3
]
</screen>
This is used as the return value to represent ARRAY_REF. For example,
"actives" file of &fml4; consists of lines which have plural space
separeted entries. So it can be representated as a type of array.
<screen>
rudo@nuinui.net	s=skip m=xxx.yyy.z # commnet

rudo@nuinui.net => [
        s=skip
        m=xxx.yyy.z
        # comment
]
</screen>
</para>

<para>
If retrieval value could be represented as ARRAY_REF, argument of
store operations alsot needs ARRAY_REF.
</para>

<para>
It is summarized as follows.
The argument is one of "nothing", "STR" or ARRAY_REF.
The return value is either of STR of ARRAY_REF (array reference).
<screen>
argument     return value
---------------------------------------
none      => STR

STR       => STR

none      => [STR, STR, ... ]

STR       => [STR, STR, ... ]
</screen>
</para>

</sect1>


<sect1 id="module.io.adapter.map.file">
	<title>
	File Map
	</title>

<para>
"file:/some/where/file/name" or file name "/some/where/file/name" map
is abstraction of IO to/from a text file.
The format of text file is space separated.
</para>

</sect1>


<sect1 id="module.io.adapter.map.unixgroup">
	<title>
	Unixgroup Map
	</title>

<para>
Abstraction of /etc/group. IO is read only.
</para>

<para>
For example, the access to 
<screen>
wheel:*:0:root,rudo,kenken
</screen>
in /etc/group is "unixgroup:wheel" map in IO::Adapter.
<screen>
$obj = new IO::Adapter "unixgroup:wheel";
</screen>
If you call get_next_key() method for this object,
you will get the member of wheel group sequentially.
In other words the wheel group is regarded as the following file
by IO::Adapter.
<screen>
root
rudo
kenken
</screen>
</para>

</sect1>


<sect1 id="module.io.adapter.map.nis">
	<title>
	Nis Map
	</title>

<para>
It is same as one of /etc/group but the data is retrieved from NIS/YP.
</para>

</sect1>


<sect1 id="module.io.adapter.map.mysql">
	<title>
	MySQL Map
	</title>

<para>
For easy maintenance, it is better to write all mysql configurations
in one file. For example, it is good that we have only to write SQL
configurations in config.cf.
</para>

<para>
But we identify plural mysql conditions. So, we use the tag
[mysql:members] to declare one region between a tag to the next tag or
=cut. It is similar to .ini file format used on Microsoft OS. We use
the tags like this:
<screen>
config.cf example

member_maps     =       mysql:members

recipient_maps  =       mysql:recipients

[mysql:members]

sql_server      =       localhost
sql_user        =       fml
sql_password    =       uja
sql_database    =       fml
sql_table       =       ml

sql_find	=	select * from ...

		...
</screen>
</para>

<para>
In calling IO::Adapter, use 
<screen>
new IO::Adapter "mysql:members", $config;
</screen>
where $config is a hash reference holding some paremeters like this:
<screen>
$config => {
	[mysql:members] => {
		sql_sever => localhost
			...	
	}
}
</screen>
FML::Config prepares this $config by reading .cf files. Hence, we
usually use FML::Config object as an argument of IO::Adapter::new()
method.
</para>


<sect2>
	<title>
	Discussion:
	How To Write SQL Statements In config.cf ?
	(fml-devel 204)
	</title>

<para>
How about lexical scope ? The .cf files cannot contain all variables
since lexical scope variables exist.
We use &amp;varname syntax for such lexical scope variables.
</para>

<para>
For example, use different member and recipient maps. In SQL
statements, the difference is a flag (fml_recipient) in a table. For
example, consider the case that "where" statement has different value
but it is determined lexically in calling MySQL.
<screen>
member_maps 	= 	mysql:members

recipient_maps 	= 	mysql:recipients


[mysql:members]

sql_server	=	localhost
sql_user	=	fml
sql_password	=	uja
sql_database	=	fml
sql_table	=	ml

sql_get_next_key =	select fml_address from $sql_table
			where fml_ml = '$ml_name'
					and
				fml_domain = '$ml_domain'

sql_getline	=	select * from $sql_table
			where fml_ml = '$ml_name'
					and
				fml_domain = '$ml_domain'

sql_add		=	insert into $sql_table
			values ('$ml_name', '$ml_domain', '&amp;address', 1, 1)

sql_delete	=	delete from $sql_table
			where	fml_ml = '$ml_name'
					and
				fml_domain = '$ml_domain'
					and
				fml_address = '&amp;address'

sql_find	=	select * from $sql_table
			where	fml_ml = '$ml_name'
					and
				fml_domain = '$ml_domain'
					and
				fml_address like '&amp;regexp'



[mysql:recipients]

sql_server	=	localhost
sql_user	=	fml
sql_password	=	uja
sql_database	=	fml
sql_table	=	ml

sql_get_next_key =	select fml_address from $sql_table
			where fml_ml = '$ml_name'
					and
				fml_domain = '$ml_domain'
					and
				fml_recipient = '1'

sql_getline	=	select * from $sql_table
			where fml_ml = '$ml_name'
					and
				fml_domain = '$ml_domain'
					and
				fml_recipient = '1'

sql_add		=	update ml
			set recipient = 1
			where fml_ml = '$ml_name'
					and
				fml_domain = '$ml_domain'
					and
				fml_address = '&amp;address'

sql_delete	=	update ml
			set recipient = 0
			where fml_ml = '$ml_name'
					and
				fml_domain = '$ml_domain'
					and
				fml_address = '&amp;address'


sql_find	=	select * from $sql_table
			where	fml_ml = '$ml_name'
					and
				fml_domain = '$ml_domain'
					and
				fml_recipient = '1'
					and
				fml_address like '&amp;regexp'
</screen>
</para>

</sect2>


</sect1>


</chapter>