#### /docs/yolk.tex

http://github.com/ThomasLocke/yolk
TeX | 2095 lines | 1622 code | 410 blank | 63 comment | 148 complexity | bf7c3ec6465512a6b9a77b63782c3d0e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1%% LyX 2.0.0 created this file.  For more info, see http://www.lyx.org/.
2%% Do not edit unless you really know what you are doing.
3\documentclass[12pt,english]{article}
4\usepackage{helvet}
5\renewcommand{\familydefault}{\sfdefault}
6\usepackage[T1]{fontenc}
7\usepackage[latin9]{inputenc}
8\usepackage{listings}
9\usepackage[a4paper]{geometry}
10\geometry{verbose,tmargin=2cm,bmargin=2cm,lmargin=2cm,rmargin=2cm}
11\setlength{\parskip}{\medskipamount}
12\setlength{\parindent}{0pt}
13\usepackage{babel}
14\usepackage[unicode=true]
15 {hyperref}
16
17\makeatletter
18%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands.
19\newenvironment{lyxcode}
20{\par\begin{list}{}{
21\setlength{\rightmargin}{\leftmargin}
22\setlength{\listparindent}{0pt}% needed for AMS classes
23\raggedright
24\setlength{\itemsep}{0pt}
25\setlength{\parsep}{0pt}
26\normalfont\ttfamily}%
27 \item[]}
28{\end{list}}
29
30\makeatother
31
32\begin{document}
33
34\title{Yolk Manual}
35
36
37\date{Revised December 11th. 2012}
38
39\maketitle
40\newpage{}
41
42\tableofcontents{}
43
44\newpage{}
45
46
47\part{General Information}
48
49
51
52This document is copyright (C) 2010-, Thomas Lřcke. You may copy this
53document, in whole or in part, in any form or by any means, as is
54or with alterations, provided that (1) alterations are clearly marked
55as alterations and (2) this copyright notice is included unmodified
56in any copy.
57
58Yolk is GPLv3 software. You should have received a copy of the GNU
59General Public License and a copy of the GCC Runtime Library Exception
60along with this program; see the files COPYING3 and COPYING.RUNTIME
62
63
64\section{What is Yolk?}
65
66Yolk is a collection of packages that aim to help build solid web-applications
67using Ada. Yolk itself doesn't do a whole lot that can't be accomplished
69and the \href{http://libre.adacore.com/libre/tools/gnat-component-collection/}{GNAT Component Collection (GNATcoll)},
70but it does make the job of building complete web-applications a bit
71simpler. Things like changing user for the running application, catching
72POSIX signals such as SIGKILL, sending log data to syslogd, adding
73basic static content handlers, creating and starting/stopping an AWS
74powered HTTP server and building Atom syndication XML are all made
75a bit easier with Yolk.
76
77A Yolk application is in reality an AWS application, with some sugar
78added, so you're not really building a Yolk web-application, as much
79as you're building an AWS web-application. What I'm getting at, is
80that you need to understand how to use AWS, in order for Yolk to make
81any kind of sense. What you get when using Yolk is the little things
82that AWS does not readily provide.
83
84
85\subsection{The Yolk demo application}
86
88to use Yolk, but please consider taking a closer look at the Yolk
89demo application to get a feel for how Yolk is actually used. The
90demo is heavily commented, so it should be fairly easy to understand
91what's going on. The demo application is also very suitable as a foundation
92for other AWS/Yolk applications.
93
94It is much easier to show how to use Yolk, than it is to write down
95all possible usage scenarios. With the combination of this manual,
96the Yolk source files and the demo application, you should be able
97to make full use of the Yolk packages in your own applications.
98
99
100\subsection{The source code}
101
102The Yolk source code is the best documentation there is. This document
103is never going to be as comprehensive as the actual source, so I'll
104strongly suggest having the source code available as you read this
105document. What you will find in this document are short descriptions
106of what a package is meant to do and perhaps small usage examples,
107not a complete rundown of every type and procedure in a package.
108
109
110\subsection{Building and installing Yolk}
111
112See the README and INSTALL files. These are found in the Yolk root
113directory.
114
115
116\subsection{The files Yolk depend upon}
117
118When you read this document and the Yolk source code, you'll notice
119that quite a few packages depend on various files being available
120at specified locations. This is for example the case with the \emph{Yolk.Whoops}
121package that expects its template file to be found at the path \emph{templates/system/500.tmpl}
122
123All such {}dependencies'' will of course be noted accordingly
124as we go along, but instead of forgetting one or more in your own
125application, I'd much rather encourage using the demo application
126as a foundation for your own applications, since all these fixed paths
127and files has been properly added to the demo.
128
129I also recommend compiling and running the demo, to make sure your
131and \emph{demo/INSTALL} files for instructions on how to get it up
132and running.
133
134
135\subsection{The Yolk packages naming}
136
137The Yolk packages are pretty diverse, ranging from process control
138to sending email. I've tried naming them as sensibly as possible,
139in the hope that the package names alone give away their function.
140If I've failed, well, you're just going to have to refer to this document
141or take a look at the source for yourself.
142
143\newpage{}
144
145
146\part{The Yolk Packages}
147
148
149\section{Yolk}
150
151The Yolk main package currently only contain only a few things: The
152Yolk \emph{Version} string, a \emph{Config\_File} function to get
153the location of the configuration file and a \emph{PID\_File} function
154to get the location of the PID file. These are used in a few places,
155for example in the \emph{directory.tmpl} template file (the version
156string), in the \emph{Yolk.Configuration} package (the \emph{Config\_File}
157function) and in the \emph{Yolk.Process\_Control} package (the \emph{PID\_File}
158function).
159
160All Yolk applications accepts two commandline arguments:
161\begin{itemize}
162\item \emph{--yolk-config-file} : Defines the location of the configuration
163file. If empty or not set, then use the default location \emph{configuration/config.ini}.
164\item \emph{--pid-file} : Defines the location of the PID file. If empty
165or not set, then don't write a PID file. Note that if you use the
166\emph{extras/rc.yolk} script to control your application, then this
167is handled for you transparently.
168\end{itemize}
169
170\section{Yolk.Cache.Discrete\_Keys}
171
172If a piece of data doesn't change very often and it is expensive to
173build, then caching it might be worthwhile. Instead of going to a
174file or database on every hit, you simply go to the cache and grab
176at the cost of some memory.
177
178If you know exactly what you want to cache, the \emph{Yolk.Cache.Discrete\_Keys}
179package might be just what you need.
180
181
182\subsection{The generic formal parameters}
183
184These are:
185
186\begin{minipage}[t]{1\columnwidth}%
188generic
189   type Key_Type is (<>);
190   type Element_Type is private;
191   Max_Element_Age : Duration := 3600.0;
192package Yolk.Cache.Discrete_Keys is
193...
194\end{lstlisting}
195%
196\end{minipage}
197
198The \emph{Max\_Element\_Age} defaults to one hour. You should obviously
199set this to whatever suits your needs. This timer is used for all
200content in the cache. You cannot set this individually for each element.
201
202
203\subsection{Instantiation}
204
205If for example we have two different sets of data (Foo and Bar) that
206are expensive to build, we can instantiate a \emph{Discrete\_Keys}
207package to handle this:
208
209\begin{minipage}[t]{1\columnwidth}%
211type Cache_Keys is (Foo, Bar);
212package My_Cache is new Yolk.Cache.Discrete_Keys
213  (Key_Type     => Cache_Keys,
214   Element_Type => Unbounded_String);
215\end{lstlisting}
216%
217\end{minipage}
218
219And that is all. We now have a \emph{My\_Cache} object that can hold
220two objects: \emph{Foo} and \emph{Bar}. These are of the type \emph{Unbounded\_String}
221and they have a \emph{Max\_Element\_Age} of 3600.0 seconds.
222
223
224\subsection{Writing to the cache}
225
226Before we can read something from the cache, we must first write something
227to it:
228
229\begin{minipage}[t]{1\columnwidth}%
231declare
232   Foo_Value : Unbounded_String := To_Unbounded_String ("Foo");
233begin
234   My_Cache.Write (Key   => Foo,
235                   Value => Foo_Value);
236end;
237\end{lstlisting}
238%
239\end{minipage}
240
241That is all it takes: {}Foo'' is now safely tucked away in the
242\emph{My\_Cache} object, and will be so for 3600.0 seconds. Calling
243\emph{Write} with the \emph{Foo }key will always overwrite earlier
244written \emph{Foo} elements, no matter their age.
245
246
248
249A cache obviously only makes sense if you intend to read from it.
250In our case we want to get our hands on the previously written {}Foo''
251value:
252
253\begin{minipage}[t]{1\columnwidth}%
255declare
256   Valid : Boolean := False;
257   Value : Unbounded_String;
258begin
260                  Is_Valid => Valid,
261                  Value    => Value);
262   if Valid then
263      --  do something interesting with the data
264   else
265      --  the Foo data is invalid.
266   end if;
267end;
268\end{lstlisting}
269%
270\end{minipage}
271
272In order for an element to be valid (the\emph{ Is\_Valid} parameter
273is true), it must:
274\begin{enumerate}
275\item have been added to the cache in the first place
276\item be younger than \emph{Max\_Element\_Age}
277\end{enumerate}
278If \emph{Is\_Valid} is \emph{False}, then \emph{Value} is undefined.
279Note that if \emph{Is\_Valid} is \emph{False} then \emph{Key} is removed
280from the cache, if it exists.
281
282
283\subsection{Checking if a key is valid}
284
285If you need to check whether a specific key exists in the cache and
286is valid, then you must use the \emph{Is\_Valid} function.
287
288\begin{minipage}[t]{1\columnwidth}%
290if My_Cache.Is_Valid (Foo) then
291   --  Foo is good!
292else
294end if;
295\end{lstlisting}
296%
297\end{minipage}
298
299This follows the same rules as the \emph{Is\_Valid} parameter for
301
302
303\subsection{Clearing keys and the entire cache}
304
305For clearing of keys and the entire cache we have, naturally, two
306\emph{Clear} procedures:
307
308\begin{minipage}[t]{1\columnwidth}%
310-- First we clear the Foo key
311My_Cache.Clear (Key => Foo);
312
313--  And then we clear the entire cache
314My_Cache.Clear;
315\end{lstlisting}
316%
317\end{minipage}
318
319And that's all it takes.
320
321
322\subsection{Cleanup - Getting rid of stale elements}
323
324Calling Cleanup will delete all stale elements from the cache:
325
326\begin{minipage}[t]{1\columnwidth}%
328My_Cache.Cleanup;
329\end{lstlisting}
330%
331\end{minipage}
332
333Note that this is potentially a very expensive operation if the cache
334is large, as the entire cache is iterated and every element tested
335for its age. Use with care.
336
337
338\section{Yolk.Cache.String\_Keys}
339
340This package is almost similar to the \emph{Yolk.Cache.Discrete\_Keys}
341package. The biggest difference is that where the \emph{Discrete\_Keys}
342cache package requires that you define a type for the keys, this package
343use regular \emph{String} as keys.
344
345The implications of this difference between the two cache packages
346are subtle. Both have the same \emph{Read}, \emph{Write}, \emph{Is\_Valid}
347and \emph{Clear} procedures and functions, so in that sense the two
348packages are the same. The biggest difference lies in the available
349generic formal parameters and the functionality of the \emph{Cleanup}
350procedure.
351
352
353\subsection{The generic formal parameters}
354
355These are:
356
357\begin{minipage}[t]{1\columnwidth}%
359generic
360   type Element_Type is private;
361   Cleanup_Size      : Positive := 200;
362   Cleanup_On_Write  : Boolean  := True;
363   Max_Element_Age   : Duration := 3600.0;
364   Reserved_Capacity : Positive := 100;
365package Yolk.Cache.Discrete_Keys is
366...
367\end{lstlisting}
368%
369\end{minipage}
370
371When the amount of elements in the cache >= \emph{Cleanup\_Size},
372then the \emph{Cleanup} procedure is called by \emph{Write}, if \emph{Cleanup\_On\_Write}
373is set to Boolean \emph{True}. \emph{Cleanup\_Size} is a sort of failsafe
374for this cache package. Since we can't know for sure what is being
375added (we don't know the keys beforehand), we need to make sure it
376doesn't gobble up all available resources. Set this number high enough
377that it'll never tricker under normal circumstances, but low enough
378that it'll prevent resource exhaustion in case of errors.
379
380The \emph{Max\_Element\_Age} defaults to one hour. You should obviously
381set this to whatever suits your needs. This timer is used for all
382content in the cache. You cannot set this individually for each element.
383
384\emph{Reserved\_Capacity} should be set as close as possible to the
385expected final size of the cache. If your best guestimate is 200 elements
386in the cache, then set this to 200. Note that this setting has no
387bearing on the actual size of the cache. The cache will happily grow
388beyond the \emph{Reserved\_Capacity} value.
389
390
391\subsection{Instantiation}
392
393Instantiating \emph{String\_Keys} is done like this:
394
395\begin{minipage}[t]{1\columnwidth}%
397package My_Cache is new Yolk.Cache.String_Keys
398  (Element_Type      => Unbounded_String,
399   Reserved_Capacity => 200);
400\end{lstlisting}
401%
402\end{minipage}
403
404And that is all. We now have a \emph{My\_Cache} object that can hold
405objects of the type \emph{Unbounded\_String}, all of which have a
406\emph{Max\_Element\_Age} of 3600.0 seconds. Also we've told the cache
407to set aside at least 200 positions for content.
408
409
410\subsection{Writing to the cache}
411
412Before we can read something from the cache, we must first write something
413to it:
414
415\begin{minipage}[t]{1\columnwidth}%
417declare
418   Value : Unbounded_String := To_Unbounded_String ("42");
419begin
420   My_Cache.Write (Key   => "Foo",
421                   Value => Value);
422end;
423\end{lstlisting}
424%
425\end{minipage}
426
427{}42'' is now safely tucked away in the \emph{My\_Cache} object
428under the key {}Foo'', and will be so for 3600.0 seconds. Calling
429\emph{Write} with the {}Foo''\emph{ }String will always overwrite
430earlier written {}Foo'' elements, no matter their age.
431
432
434
435A cache obviously only makes sense if you intend to read from it.
436In our case we want to get our hands on the previously written {}Foo''
437value:
438
439\begin{minipage}[t]{1\columnwidth}%
441declare
442   Valid : Boolean := False;
443   Value : Unbounded_String;
444begin
446                  Is_Valid => Valid,
447                  Value    => Value);
448   if Valid then
449      --  do something interesting with the data
450   else
451      --  the Foo data is invalid.
452   end if;
453end;
454\end{lstlisting}
455%
456\end{minipage}
457
458In order for an element to be valid (the\emph{ Is\_Valid} parameter
459is true), it must:
460\begin{enumerate}
461\item have been added to the cache in the first place
462\item be younger than \emph{Max\_Element\_Age}
463\end{enumerate}
464If \emph{Is\_Valid} is \emph{False}, then \emph{Value} contains undefined
465garbage. Note that if \emph{Is\_Valid} is \emph{False} then \emph{Key}
466is removed from the cache, if it exists.
467
468
469\subsection{Checking if a key is valid}
470
471If you need to check whether a specific key exists in the cache and
472is valid, then you need to use the \emph{Is\_Valid} function.
473
474\begin{minipage}[t]{1\columnwidth}%
476if My_Cache.Is_Valid ("Foo") then
477   --  Foo is good!
478else
480end if;
481\end{lstlisting}
482%
483\end{minipage}
484
485This follows the same rules as the \emph{Is\_Valid} parameter for
487
488
489\subsection{Clearing keys and the entire cache}
490
491For clearing of keys and the entire cache we have, naturally, two
492\emph{Clear} procedures:
493
494\begin{minipage}[t]{1\columnwidth}%
496-- First we clear the Foo key
497My_Cache.Clear (Key => "Foo");
498
499--  And then we clear the entire cache
500My_Cache.Clear;
501\end{lstlisting}
502%
503\end{minipage}
504
505
506\subsection{How much is in there?}
507
508With the \emph{Discrete\_Keys} cache we obviously always know the
509exact amount of keys available, since we've defined the keys ourselves.
510This is not the case with the \emph{String\_Keys} cache, where any
511\emph{String} can be a key. If we need to know how many elements that
512are currently in the cache, we call the \emph{Length} function:
513
514\begin{minipage}[t]{1\columnwidth}%
516if My_Cache.Length > 1000 then
517   --  Woa! Lots of stuff in the cache..
518end if;
519\end{lstlisting}
520%
521\end{minipage}
522
523Note that \emph{Length} count both valid and invalid elements.
524
525
526\subsection{Cleanup - Keeping cache size in check}
527
528if \emph{Cleanup\_On\_Write} is \emph{True}, then \emph{Cleanup} is
529called by \emph{Write }whenever the size of the cache reach \emph{Cleanup\_Size}.
530It is of course also possible to call it manually:
531
532\begin{minipage}[t]{1\columnwidth}%
534if My_Cache.Length > 1000 then
535   My_Cache.Cleanup;
536end if;
537\end{lstlisting}
538%
539\end{minipage}
540
541If you've set \emph{Cleanup\_On\_Write} to Boolean \emph{False} and
542the String keys are coming from outside sources, then you really should
543make sure you call \emph{Cleanup} on a regular basis.
544
545
546\section{Yolk.Command\_Line}
547
548This package enables you to fetch the value of a given commandline
549parameter using the \emph{Get} function:
550
551\begin{minipage}[t]{1\columnwidth}%
553function Get
554  (Parameter : in String;
555   Default   : in String := "")
556   return String;
557\end{lstlisting}
558%
559\end{minipage}
560
561If \emph{Parameter} is found \emph{Get} will return the value immediately
562following \emph{Parameter.} If \emph{Parameter} isn't found \emph{Default}
563is returned.
564
565
566\section{Yolk.Config\_File\_Parser}
567
568This package enables you to access KEY/VALUE pairs in configuration
569files that are written in the style:
570\begin{lyxcode}
571\#~This~is~a~comment
572
573-{}-~This~is~also~a~comment
574
575KEY~VALUE
576\end{lyxcode}
577Keys are case-insensitive, so \emph{FOO}, \emph{foo} and \emph{fOo}
578are all the same.\emph{ }Blank lines and comments are ignored and
579so is pre/postfixed whitespace. It is not necessary to quote values
580that contain whitespace, to this:
581\begin{lyxcode}
582KEY~some~value~with~whitespace
583\end{lyxcode}
584is perfectly valid, and will return {}\emph{some value with whitespace}''
585when calling \emph{Get (KEY)}. If VALUE is \emph{Boolean} \emph{True}
586or \emph{False} (case-insensitive), then the KEY can be returned as
587a \emph{String} or a \emph{Boolean}, depending on the target type.
588If the target type does not match the VALUE and no sensible conversion
589can be made, then a \emph{Conversion\_Error} exception is raised.
590No dummy values are returned at any time.
591
592To clear a default value, simply add the key to the configuration
593file, with no value set.
594
595
596\subsection{The generic formal parameters}
597
598These are:
599
600\begin{minipage}[t]{1\columnwidth}%
602generic
604   type Key_Type is (<>);
605   type Defaults_Array_Type is array (Key_Type) of Unbounded_String;
606   Defaults    : in Defaults_Array_Type;
607   Config_File : in String;
608package Yolk.Config_File_Parser is
609...
610\end{lstlisting}
611%
612\end{minipage}
613
614\emph{Config\_File} is of course the name and location of the configuration
615file.
616
617
618\subsection{Exceptions}
619
620There are 3 different exceptions that can be raised by the \emph{Yolk.Config\_File\_Parser}
621package. These are:
622\begin{itemize}
623\item \emph{Unknown\_Key}. This is raised if an unknown key has been found
624in the configuration file given when instantiating the package or
626\item \emph{Cannot\_Open\_Config\_File}. This is raised when \emph{Config\_File}
628\item \emph{Conversion\_Error}. This is raised when a value cannot be converted
629to the target type, ie. the value {}42'' to a \emph{Boolean}.
630\end{itemize}
631
632\subsection{Instantiation}
633
634\emph{Yolk.Config\_File\_Parser} is a generic package, so in order
635to use it, you have to instantiate it, like this:
636
637\begin{minipage}[t]{1\columnwidth}%
639package My_Configuration is
640
641   type Keys is (Foo, Bar);
642   type Defaults_Array is array (Keys) of Unbounded_String;
643
644   Default_Values : constant Defaults_Array :=
645                      (Foo => To_Unbounded_String ("some foo"),
646                       Bar => To_Unbounded_String ("some bar"));
647
648   package Config is new Yolk.Config_File_Parser
649     (Key_Type => Keys,
650      Defaults_Array_Type => Defaults_Array,
651      Defaults => Default_Value,
652      Config_File => "config.ini");
653
654end My_Configuration;
655\end{lstlisting}
656%
657\end{minipage}
658
659Here we instantiate the \emph{Config} package with \emph{config.ini}
660as the configuration file. This means that KEY/VALUE pairs found in
661this file will overwrite the default values set in the \emph{Default\_Values}
662array. Setting a default value to \emph{Null\_Unbounded\_String} means
663the value is empty.
664
665Note that the \emph{config.ini} file does not have to contain all
666the valid keys. It is perfectly fine to only add those keys that have
667non-default values to the configuration file.
668
669
671
674
675\begin{minipage}[t]{1\columnwidth}%
678\end{lstlisting}
679%
680\end{minipage}
681
682Now the KEY/VALUE pairs of \emph{new\_config.ini} will overwrite the
683ones originally found in the \emph{config.ini} file the package was
684instantiated with. You can do this as many times as you like. Note
685that you cannot change what KEY's are valid, so if the \emph{new\_config.ini}
686file contains unknown keys, \emph{Load\_File} will raise the \emph{Unknown\_Key}
687exception.
688
689
690\subsection{Getting values}
691
693it is now time to get to the configuration values. To get the value
694of the \emph{Foo} key, you do:
695
696\begin{minipage}[t]{1\columnwidth}%
698My_Configuration.Config.Get (Foo);
699\end{lstlisting}
700%
701\end{minipage}
702
703There are Get functions for the following types:
704\begin{itemize}
705\item \emph{Boolean}
706\item \emph{Duration}
707\item \emph{Float}
708\item \emph{Integer}
709\item \emph{String}
710\item \emph{Unbounded\_String}
711\end{itemize}
712Empty keys simply return an empty \emph{String} or a \emph{Null\_Unbounded\_String},
713depending on the target type. If a key is empty and the target type
714is not a \emph{String} or an \emph{Unbounded\_String}, then the \emph{Conversion\_Error}
715exception is raised.
716
717
718\subsection{Checking if a KEY has a VALUE}
719
720You can check if a key has a value with the \emph{Has\_Value} function:
721
722\begin{minipage}[t]{1\columnwidth}%
724if Has_Value (Foo) then
725   Put_Line ("Foo has a value");
726end if;
727\end{lstlisting}
728%
729\end{minipage}
730
731Basically all this function does is return \emph{Boolean} \emph{True}
732if the value of the given key is not a \emph{Null\_Unbounded\_String}.
733
734
735\section{Yolk.Configuration}
736
737This package is a bit of an oddball, as all it does is instantiate
738the \emph{Yolk.Config\_File\_Parser} generic with the default AWS
739and Yolk configuration values. This is used by Yolk internally, but
740also by the AWS component of your application. The instantiation looks
741like this:
742
743\begin{minipage}[t]{1\columnwidth}%
745package Config is new Config_File_Parser
746  (Key_Type            => Keys,
747   Defaults_Array_Type => Defaults_Array,
748   Defaults            => Default_Values,
749   Config_File         => Config_File);
750\end{lstlisting}
751%
752\end{minipage}
753
754The \emph{Config\_File} function call return either the default Yolk
755configuration file (\emph{configuration/config.ini}) or a user specified
756configuration file given by the \emph{--yolk-config-file} command
757line argument, so\emph{ }starting for example the Yolk demo like this:
758\begin{lyxcode}
759./yolk\_demo~-{}-yolk-config-file~/etc/yolk-config.ini
760\end{lyxcode}
761will force the demo to look for the \emph{/etc/yolk-config.ini} configuration
762file.
763
764There's a fully commented \emph{config.ini.dist} file available in
765the \emph{extras/} directory. I recommend taking a look at the Yolk
766demo application to see how the \emph{Yolk.Configuration} package
767is used.
768
769
770\subsection{Get the AWS specific configuration settings}
771
772On some occassions it might be necessary to get the AWS configuration
773object. This can easily be accomplished by calling the \emph{Get\_AWS\_Configuration}
774function:
775
776\begin{minipage}[t]{1\columnwidth}%
778AWS_Config : constant AWS.Config.Object :=
779  Yolk.Configuration.Get_AWS_Configuration;
780\end{lstlisting}
781%
782\end{minipage}
783
784
785\section{Yolk.Email}
786
787Using \emph{Yolk.Email} and the child package \emph{Yolk.Email.Composer}
788you can build and send more or less any kind of email:
789\begin{itemize}
790\item Plain text
791\item Multipart/Alternative
792\item Multipart/Mixed
793\end{itemize}
794The package supports adding multiple SMTP servers, meaning you can
795add as many as you need, and the email will then be send via the first
796one that accepts it.
797
798The \emph{Yolk.Email} package define 4 exceptions and 3 types. The
799facilities for actually constructing and sending the email are found
800in \emph{Yolk.Email.Composer}.
801
802
803\subsection{Exceptions}
804
805These are:
806\begin{itemize}
807\item \emph{Attachment\_File\_Not\_Found}. Is raised if a file attachment
811\item \emph{No\_Sender\_Set\_With\_Multiple\_From}. Is raised when an email
8133.6.2. http://tools.ietf.org/html/rfc5322
814\item \emph{No\_SMTP\_Host\_Set}. Is raised if the SMTP host list is empty,
815ie. no SMTP host has been set for sending the email.
816\end{itemize}
817
818\subsection{The Yolk.Email types}
819
820When using \emph{Yolk.Email.Composer} to build and send emails, three
821types declared in \emph{Yolk.Email} are central:
822\begin{enumerate}
823\item \emph{Character\_Set}
824\item \emph{Recipient\_Kind}
825\item \emph{Structure}
826\end{enumerate}
827The \emph{Character\_Set} type define what character set is used when
828data is added to an email \emph{Structure} object. For example looking
829at the \emph{Yolk.Email.Composer.Add\_From} procedure, we see that
830the \emph{Charset} parameter defaults to \emph{US\_ASCII}:
831
832\begin{minipage}[t]{1\columnwidth}%
835  (ES        : in out Structure;
837   Name      : in     String := "";
838   Charset   : in     Character_Set := US_ASCII);
839\end{lstlisting}
840%
841\end{minipage}
842
843This does not mean that \emph{Yolk.Email.Composer.Add\_From} will
844encode \emph{Name} as \emph{US\_ASCII}, instead it means that the
845data given in \emph{Name} already is \emph{US\_ASCII}. So if \emph{Name}
846had contained an ISO-8859-1 encoded \emph{String}, then the call would've
847looked like this:
848
849\begin{minipage}[t]{1\columnwidth}%
851declare
852   use Yolk.Email;
853
854   Email : Structure;
855begin
857     (ES        => Email,
859      Name      => "Alice",
860      Charset   => ISO_8859_1);
861end;
862\end{lstlisting}
863%
864\end{minipage}
865
866In this case you will end up with a From header looking like this:
867\begin{lyxcode}
868From:~=?ISO-8859-1?Q?Alice?=~<alice@domain.tld>
869\end{lyxcode}
870So bear in mind that it is your responsibility to ensure that your
871data, and the \emph{Character\_Set} parameter match.
872
873The \emph{Recipient\_Kind} type define the kind of recipient that
874is being added to an email. If you've worked with email, these three
875should be familiar to you:
876\begin{enumerate}
877\item \emph{Bcc}
878\item \emph{Cc}
879\item \emph{To}
880\end{enumerate}
881When adding recipients to an email \emph{Structure} the default is
882\emph{To}, but since not all recipients are equal, you can change
883the kind of recipient to \emph{Bcc} or \emph{Cc}, according to your
884needs.
885
886The \emph{Structure} type is at the core of it all. You declare an
887object to be of the \emph{Structure} type, and then you use the \emph{Yolk.Email.Composer}
888facilities to build and send the email.
889
890
891\section{Yolk.Email.Composer}
892
893The actual tools for building and sending an email is found in this
894package. Here are tools for building emails from the ground up and
895there are a few convenience procedures if you just need to send a
896simple email with no bells or whistles.
897
898I'm not going to go through ever procedure in this package, instead
899I'll show an example on how to build an email from the ground up and
900how to use one of the convenience procedures.
901
902
903\subsection{Building and sending an email, the easy way}
904
905There are two convenience procedures in \emph{Yolk.Email.Composer}
906for sending emails without having to do a whole lot of work/thinking.
907They are both named \emph{Send} and they look like this:
908
909\begin{minipage}[t]{1\columnwidth}%
911procedure Send
912  (ES             : in out Structure;
914   From_Name      : in     String := "";
916   To_Name        : in     String := "";
917   Subject        : in     String;
918   Text_Part      : in     String;
919   SMTP_Server    : in     String := "localhost";
920   SMTP_Port      : in     Positive := 25;
921   Charset        : in     Character_Set := US_ASCII);
922
923procedure Send
924  (ES             : in out Structure;
926   From_Name      : in     String := "";
928   To_Name        : in     String := "";
929   Subject        : in     String;
930   Text_Part      : in     String;
931   HTML_Part      : in     String;
932   SMTP_Server    : in     String := "localhost";
933   SMTP_Port      : in     Positive := 25;
934   Charset        : in     Character_Set := US_ASCII);
935\end{lstlisting}
936%
937\end{minipage}
938
939As you can see, the only difference between these two is that the
940first one sends plain text emails, while the second one sends \emph{multipart/alternative}
941with both plain text and HTML parts. Usage is as simple as:
942
943\begin{minipage}[t]{1\columnwidth}%
945declare
946   use Yolk.Email;
947
948   Email : Structure;
949begin
950   Composer.Send (ES           => Email,
952                  From_Name    => "Alice",
954                  To_Name      => "Bob",
955                  Subject      => "Is this thing on?",
956                  Text_Part    => "Hey you!",
957                  Charset      => ISO_8859_1);
958
959   if Composer.Is_Send (Email) then
960      --  Success!
961   else
962      --  Failure!
963   end if;
964end;
965\end{lstlisting}
966%
967\end{minipage}
968
969It is possible, and allowed, to call some of the various other procedures
970prior to calling one of the convenience procedures. If for example
971you want to add a custom header, it can be done like this:
972
973\begin{minipage}[t]{1\columnwidth}%
975declare
976   use Yolk.Email;
977
978   Email : Structure;
979begin
981                               Name    => "User-Agent",
982                               Value   => "My User Agent");
983
984   Composer.Send (ES           => Email,
986                  From_Name    => "Alice",
988                  To_Name      => "Bob",
989                  Subject      => "Is this thing on?",
990                  Text_Part    => "Hey you!",
991                  Charset      => ISO_8859_1);
992
993   if Composer.Is_Send (Email) then
994      --  Success!
995   else
996      --  Failure!
997   end if;
998end;
999\end{lstlisting}
1000%
1001\end{minipage}
1002
1003And with that, the header \emph{User-Agent:} is now added to the email:
1004\begin{lyxcode}
1005User-Agent:~My~User~Agent
1006\end{lyxcode}
1007It hardly gets any easier than that. Lets move on and see how the
1008above is accomplished the hard way.
1009
1010
1011\subsection{Building and sending email, the hard way}
1012
1013It is possible to build an email from the ground up, which obviously
1014allows for a more fine grained control over what is added. It is also
1015a bit more complicated, but not much. Lets try and mimick the easy
1016examples, the {}hard'' way:
1017
1018\begin{minipage}[t]{1\columnwidth}%
1020declare
1021   use Yolk.Email;
1022
1023   Email : Structure;
1024begin
1026                               Name  => "User-Agent",
1027                               Value => "My User Agent");
1028
1031                      Name    => "Alice",
1032                      Charset => ISO_8859_1);
1033
1036                           Name    => "Bob");
1037
1038   Composer.Set_Subject (ES      => Email,
1039                         Subject => "Is this thing on?");
1040
1041   Composer.Set_Text_Part (ES   => Email,
1042                           Part => "Hey you!");
1043
1045                             Host => "localhost");
1046
1047   Composer.Send (ES => Email);
1048
1049   if Composer.Is_Send (Email) then
1050      --  Success!
1051   else
1052      --  Failure!
1053   end if;
1054end;
1055\end{lstlisting}
1056%
1057\end{minipage}
1058
1059Harder yes, but really not all that much more difficult.
1060
1061
1062\section{Yolk.Handlers}
1063
1064Most web applications will need to handle static content, such as
1065PNG, HTML and CSS files. \emph{Yolk.Handlers} helps you accomplish
1066that, so you don't have to build your own handlers for these kinds
1067of files.
1068
1069The following filetypes are supported by \emph{Yolk.Handlers}:
1070\begin{itemize}
1071\item CSS
1072\item GIF
1073\item HTML
1074\item ICO
1075\item JPG
1076\item JS
1077\item PNG
1078\item SVG
1079\item XML
1080\item XSL
1081\end{itemize}
1082The filetypes that are textual, are compressed according to the \emph{Yolk.Configuration}
1083parameter \emph{Compress\_Static\_Content} which defaults to \emph{False}.
1084The regular expressions for identifying these filetypes are also defined
1085in \emph{Yolk.Configuration} by the \emph{Handler\_{*}} parameters.
1086These regular expressions are registered by the \emph{AWS.Services.Dispatchers.URI.Register\_Regexp}
1087procedure.
1088
1089There's only one procedure in the \emph{Yolk.Handlers} package:
1090
1091\begin{minipage}[t]{1\columnwidth}%
1093procedure Set (RH : out AWS.Services.Dispatchers.URI.Handler);
1094\end{lstlisting}
1095%
1096\end{minipage}
1097
1098You can see an example on how this is used in the demo file \emph{my\_handlers.adb}.
1099There's really very little reason not to use this package for handling
1100of static content, but it is of course not mandatory.
1101
1102This package makes use of the \emph{Yolk.Static\_Content} package
1103for the actual delivery of the content to the user.
1104
1105
1106\section{Yolk.Log}
1107
1108This package serves two purposes:
1109\begin{enumerate}
1110\item It contains the two callback procedures used to write AWS logging
1111data (access and error) to syslogd.
1112\item It creates the SQL, SQL\_Cache, SQL\_Error, SQL\_Select, Alert, Critical,
1113Debug, Emergency, Error, Info, Notice and Warning trace handles, and
1114activates them according to the values defined in the configuration
1115file.
1116\end{enumerate}
1117Out of the box, a Yolk application requires a running syslogd daemon,
1118as all log data is sent to syslogd. If for some reason you don't want
1119to use syslogd, you're going to have to hack the \emph{Yolk.Log} package,
1120or remove it entirely.
1121
1122The two procedures named \emph{AWS\_{*}} are used by the AWS HTTP(S)
1123server. These should not be used for anything else - or rather: If
1124you use them for anything else, the \emph{Message} given is going
1125to be written to syslogd with either the AWS access log label or AWS
1126error log label. There's absolutely no harm in this, except it might
1127be a bit confusing when reading the log data.
1128
1129The \emph{Trace} procedure is the one that you will be using in your
1130application. You can send log data to the trace handles defined in
1131\emph{Yolk.Log.Trace\_Handles}. All log data is then sent to the syslogd
1132daemon using the facilities set in the configuration file for the
1133given trace handle.
1134
1135Using \emph{Trace} is about as easy as it gets:
1136
1137\begin{minipage}[t]{1\columnwidth}%
1139Yolk.Log.Trace (Handle  => Error,
1140                Message => "Secret sauce to Error!");
1141\end{lstlisting}
1142%
1143\end{minipage}
1144
1145If you haven't activated a trace handle, then calling \emph{Trace}
1146for that handle does nothing, ie. you don't have to remove all your
1147\emph{Trace} calls from the code if you don't use them.
1148
1149Note that on many systems the Emergency messages are written to console,
1151certain that you can get to the messages.
1152
1153
1154\section{Yolk.Not\_Found}
1155
1156The job of this package is to return a HTTP 404 status code and an
1158\emph{Generate} is about as simple as they come:
1159
1160\begin{minipage}[t]{1\columnwidth}%
1162function Generate
1163  (Request : in AWS.Status.Data)
1164   return AWS.Response.Data;
1165\end{lstlisting}
1166%
1167\end{minipage}
1168
1169It relies on the template file \emph{demo/exe/templates/system/404.tmpl}
1170to generate the generic 404 HTML page, so if you want to use \emph{Yolk.Not\_Found}
1171in your own application, then remember to bring along this file. Where
1172the \emph{404.tmpl} is placed is defined in the configuration parameter
1173\emph{System\_Templates\_Path}.
1174
1175Also worth noting is that the \emph{Yolk.Not\_Found.Generate} function
1176is used as the default callback in the demo application. This means
1177that all requested resources that doesn't match a registered dispatcher,
1178is served by \emph{Yolk.Not\_Found.Generate} ie. a 404 is returned.
1180
1181
1182\section{Yolk.Process\_Control}
1183
1184With \emph{Yolk.Process\_Control} you get the ability to control your
1185application using the SIGINT, SIGPWR and SIGTERM signals. If you give
1186your Yolk application the \emph{--pid-file} commandline argument when
1187starting it, \emph{Yolk.Process\_Control} will create a PID file on
1188the given location, if it is allowed to do so. This PID file will
1189also be deleted when the application terminates. Note that the \emph{extras/rc.yolk}
1190script handles all this transparently.
1191
1192
1193\subsection{Exceptions}
1194
1195These are:
1196\begin{itemize}
1197\item \emph{Cannot\_Create\_PID\_File}. Is raised if the \emph{PID\_File}
1198cannot be created, eg. if the application lacks permissions to write
1199to the directory where the \emph{PID\_File} is located.
1200\item \emph{Cannot\_Delete\_PID\_File}. Is raised if the \emph{PID\_file}
1201cannot be deleted, eg. if the application lacks permissions to write
1202to the directory where the \emph{PID\_File} is located, or to the
1203\emph{PID\_File} itself.
1204\item \emph{PID\_File\_Exists}. Is raised when the \emph{PID\_File} already
1205exists, ie. the application is already running or it was shutdown
1206incorrectly.
1207\end{itemize}
1208
1209\subsection{Using Yolk.Process\_Control}
1210
1211When you use the \emph{Yolk.Process\_Control} package the \emph{Unreserve\_All\_Interrupts}
1212pragma is used. This means that depending on the compiler used one
1213or more interrupt signals may be affected. In the case of the GNAT
1214compiler, this is specifically mentioned in the source of the \emph{Ada.Interrupts.Names}
1215package:
1216\begin{quote}
1217-- The pragma Unreserve\_All\_Interrupts affects the following signal(s):
1218
1220\end{quote}
1221Since neither SIGPWR or SIGTERM are reserved by the compiler, the
1222\emph{Yolk.Process\_Control} package is able to assume control of
1224If you compile Yolk with a different compiler than GNAT, then please
1225check if one of the affected signals are reserved.
1226
1227There are two procedures in the \emph{Yolk.Process\_Control} package:
1228
1229\begin{minipage}[t]{1\columnwidth}%
1231procedure Stop;
1232
1233procedure Wait;
1234\end{lstlisting}
1235%
1236\end{minipage}
1237
1238When you call the \emph{Wait} procedure, you basically hang there
1239until
1240\begin{enumerate}
1241\item The \emph{Stop} procedure is called
1242\item The application receives a SIGINT, SIGPWR or SIGTERM signal
1243\end{enumerate}
1244This is quite handy for applications, that need some sort of loop
1245to keep them from terminating. You can see an example on how this
1246can be done in the \emph{demo/src/yolk\_demo.adb} file.
1247
1248When \emph{Wait} is called, subsequent calls to \emph{Wait} are ignored,
1249unless a call to \emph{Stop} has been made or the application has
1250received one of the SIGINT, SIGPWR or SIGTERM signals. So it's perfectly
1251valid to do:
1252
1253\begin{minipage}[t]{1\columnwidth}%
1255Wait;
1256--  Stop called from somewhere in the app
1257--  Do something...
1258Wait;
1259--  The app receives a SIGINT signal
1260--  Do something...
1261Wait;
1262\end{lstlisting}
1263%
1264\end{minipage}
1265
1266Whether or not this is actually useful I don't know, but it is possible.
1267
1268
1269\section{Yolk.Process\_Owner}
1270
1271When it is necessary to change the owner of a process, the \emph{Yolk.Process\_Owner}
1272package is the solution. Obviously this can also be done when starting
1273the application, using various shell tricks, but I find it it much
1274cleaner to just let the application handle it by itself.
1275
1276
1277\subsection{Exceptions}
1278
1279There's only one:
1280\begin{enumerate}
1282doesn't exist on the system.
1283\end{enumerate}
1284
1285\subsection{Using Yolk.Process\_Owner}
1286
1287There's only a single procedure in this package and its specification
1288looks like this:
1289
1290\begin{minipage}[t]{1\columnwidth}%
1292procedure Set_User
1294  --  Set the process owner to Username.
1295\end{lstlisting}
1296%
1297\end{minipage}
1298
1299Please note that when changing the user ID of the application with
1300\emph{Set\_User}, the group ID is changed to the first group the given
1301user is a member of.
1302
1303Usage is as simple as expected:
1304
1305\begin{minipage}[t]{1\columnwidth}%
1307declare
1308begin
1310exception
1312      --  User is missing. Do something!
1313end;
1314\end{lstlisting}
1315%
1316\end{minipage}
1317
1318In the file \emph{demo/src/yolk\_demo.adb} you'll find that \emph{Yolk.Process\_Owner.Set\_User}
1319is used in conjunction with the \emph{Yolk.Configuration.Yolk\_User}
1320parameter.
1321
1322
1323\section{Yolk.Server}
1324
1325This is a convenience package to handle creating, starting and stopping
1326an AWS HTTP server. The biggest drawback to this package is that it
1327can only create and manage \emph{one} AWS server.
1328
1329Note a potential manual operation when using the \emph{Yolk.Server
1330}package : Setting the \emph{Cache-Control} header. This can become
1331necessary if you
1332\begin{enumerate}
1333\item use \emph{Yolk.Server} to create and start your AWS server AND
1334\item use the \emph{Yolk.Handlers} package to register dispatchers for static
1335content AND
1336\item have the \emph{Compress\_Static\_Content} configuration parameter
1337set to \emph{True }AND
1338\item aren't content with the default \emph{Cache-Control} header
1339\end{enumerate}
1340In that case you can use the \emph{Yolk.Static\_Content.Set\_Cache\_Options}
1342sent to clients requesting static content. See the Yolk.Static\_Content
1344
1345
1346\subsection{Yolk.Server.Create}
1347
1348Creating a server is done by calling the \emph{Create} function. This
1349function accepts one parameter that should be fairly self-explanatory.
1350
1351\begin{minipage}[t]{1\columnwidth}%
1353type HTTP is tagged limited private;
1354
1355function Create
1356  (Unexpected : in AWS.Exceptions.Unexpected_Exception_Handler)
1357   return HTTP;
1358\end{lstlisting}
1359%
1360\end{minipage}
1361
1362
1363\subsection{Yolk.Server.Start}
1364
1365\begin{minipage}[t]{1\columnwidth}%
1367procedure Start
1368  (WS          : in out HTTP;
1369   Dispatchers : in     AWS.Dispatchers.Handler'Class);
1370\end{lstlisting}
1371%
1372\end{minipage}
1373
1374This does as expected: Starts the server with\emph{ Dispatchers.}
1375
1376When calling \emph{Start} several things happen:
1377\begin{enumerate}
1378\item If the configuration parameter \emph{Load\_MIME\_Types\_File} is \emph{True}
1379then the MIME types file given in \emph{MIME\_Types\_File} is loaded
1380into AWS.
1381\item If the configuration parameter \emph{Start\_WebSocket\_Servers} is
1382\emph{True} then the AWS WebSocket servers are started.
1383\item \emph{Yolk.Static\_Content.Static\_Content\_Cache\_Setup} is called
1384with its default parameters if the configuration parameter \emph{Compress\_Static\_Content}
1385is \emph{True}.
1386\item If session support is turned on for the server and the \emph{Session\_Data\_File}
1387exists, then the session data is loaded from this file.
1388\item The \emph{Yolk.Log.AWS\_Access\_Log\_Writer} procedure is registered
1389to handle all AWS access log data if the configuration parameter \emph{AWS\_Access\_Log\_Activate}
1390is \emph{True} .
1391\item The \emph{Yolk.Log.AWS\_Error\_Log\_Writer} procedure is registered
1392to handle all AWS error log data if the configuration parameter \emph{AWS\_Error\_Log\_Activate}
1393is \emph{True} .
1394\end{enumerate}
1395
1396\subsection{Yolk.Server.Stop}
1397
1398\begin{minipage}[t]{1\columnwidth}%
1399\begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,sho…

Large files files are truncated, but you can click here to view the full file