/docs/yolk.tex
LaTeX | 2095 lines | 1622 code | 410 blank | 63 comment | 0 complexity | bf7c3ec6465512a6b9a77b63782c3d0e MD5 | raw file
Possible License(s): AGPL-1.0
- %% LyX 2.0.0 created this file. For more info, see http://www.lyx.org/.
- %% Do not edit unless you really know what you are doing.
- \documentclass[12pt,english]{article}
- \usepackage{helvet}
- \renewcommand{\familydefault}{\sfdefault}
- \usepackage[T1]{fontenc}
- \usepackage[latin9]{inputenc}
- \usepackage{listings}
- \usepackage[a4paper]{geometry}
- \geometry{verbose,tmargin=2cm,bmargin=2cm,lmargin=2cm,rmargin=2cm}
- \setlength{\parskip}{\medskipamount}
- \setlength{\parindent}{0pt}
- \usepackage{babel}
- \usepackage[unicode=true]
- {hyperref}
- \makeatletter
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands.
- \newenvironment{lyxcode}
- {\par\begin{list}{}{
- \setlength{\rightmargin}{\leftmargin}
- \setlength{\listparindent}{0pt}% needed for AMS classes
- \raggedright
- \setlength{\itemsep}{0pt}
- \setlength{\parsep}{0pt}
- \normalfont\ttfamily}%
- \item[]}
- {\end{list}}
- \makeatother
- \begin{document}
- \title{Yolk Manual}
- \date{Revised December 11th. 2012}
- \maketitle
- \newpage{}
- \tableofcontents{}
- \newpage{}
- \part{General Information}
- \section{Copyright and License}
- This document is copyright (C) 2010-, Thomas Lřcke. You may copy this
- document, in whole or in part, in any form or by any means, as is
- or with alterations, provided that (1) alterations are clearly marked
- as alterations and (2) this copyright notice is included unmodified
- in any copy.
- Yolk is GPLv3 software. You should have received a copy of the GNU
- General Public License and a copy of the GCC Runtime Library Exception
- along with this program; see the files COPYING3 and COPYING.RUNTIME
- respectively. If not, see \href{http://www.gnu.org/licenses/}{http://www.gnu.org/licenses/}.
- \section{What is Yolk?}
- Yolk is a collection of packages that aim to help build solid web-applications
- using Ada. Yolk itself doesn't do a whole lot that can't be accomplished
- simply by using \href{http://libre.adacore.com/libre/tools/aws/}{AWS}
- and the \href{http://libre.adacore.com/libre/tools/gnat-component-collection/}{GNAT Component Collection (GNATcoll)},
- but it does make the job of building complete web-applications a bit
- simpler. Things like changing user for the running application, catching
- POSIX signals such as SIGKILL, sending log data to syslogd, adding
- basic static content handlers, creating and starting/stopping an AWS
- powered HTTP server and building Atom syndication XML are all made
- a bit easier with Yolk.
- A Yolk application is in reality an AWS application, with some sugar
- added, so you're not really building a Yolk web-application, as much
- as you're building an AWS web-application. What I'm getting at, is
- that you need to understand how to use AWS, in order for Yolk to make
- any kind of sense. What you get when using Yolk is the little things
- that AWS does not readily provide.
- \subsection{The Yolk demo application}
- Reading this manual will of course (I hope!) help you understand how
- to use Yolk, but please consider taking a closer look at the Yolk
- demo application to get a feel for how Yolk is actually used. The
- demo is heavily commented, so it should be fairly easy to understand
- what's going on. The demo application is also very suitable as a foundation
- for other AWS/Yolk applications.
- It is much easier to show how to use Yolk, than it is to write down
- all possible usage scenarios. With the combination of this manual,
- the Yolk source files and the demo application, you should be able
- to make full use of the Yolk packages in your own applications.
- \subsection{The source code}
- The Yolk source code is the best documentation there is. This document
- is never going to be as comprehensive as the actual source, so I'll
- strongly suggest having the source code available as you read this
- document. What you will find in this document are short descriptions
- of what a package is meant to do and perhaps small usage examples,
- not a complete rundown of every type and procedure in a package.
- \subsection{Building and installing Yolk}
- See the README and INSTALL files. These are found in the Yolk root
- directory.
- \subsection{The files Yolk depend upon}
- When you read this document and the Yolk source code, you'll notice
- that quite a few packages depend on various files being available
- at specified locations. This is for example the case with the \emph{Yolk.Whoops}
- package that expects its template file to be found at the path \emph{templates/system/500.tmpl}
- All such {}``dependencies'' will of course be noted accordingly
- as we go along, but instead of forgetting one or more in your own
- application, I'd much rather encourage using the demo application
- as a foundation for your own applications, since all these fixed paths
- and files has been properly added to the demo.
- I also recommend compiling and running the demo, to make sure your
- Yolk install is working as intended. Just read the \emph{demo/README}
- and \emph{demo/INSTALL} files for instructions on how to get it up
- and running.
- \subsection{The Yolk packages naming}
- The Yolk packages are pretty diverse, ranging from process control
- to sending email. I've tried naming them as sensibly as possible,
- in the hope that the package names alone give away their function.
- If I've failed, well, you're just going to have to refer to this document
- or take a look at the source for yourself.
- \newpage{}
- \part{The Yolk Packages}
- \section{Yolk}
- The Yolk main package currently only contain only a few things: The
- Yolk \emph{Version} string, a \emph{Config\_File} function to get
- the location of the configuration file and a \emph{PID\_File} function
- to get the location of the PID file. These are used in a few places,
- for example in the \emph{directory.tmpl} template file (the version
- string), in the \emph{Yolk.Configuration} package (the \emph{Config\_File}
- function) and in the \emph{Yolk.Process\_Control} package (the \emph{PID\_File}
- function).
- All Yolk applications accepts two commandline arguments:
- \begin{itemize}
- \item \emph{--yolk-config-file} : Defines the location of the configuration
- file. If empty or not set, then use the default location \emph{configuration/config.ini}.
- \item \emph{--pid-file} : Defines the location of the PID file. If empty
- or not set, then don't write a PID file. Note that if you use the
- \emph{extras/rc.yolk} script to control your application, then this
- is handled for you transparently.
- \end{itemize}
- \section{Yolk.Cache.Discrete\_Keys}
- If a piece of data doesn't change very often and it is expensive to
- build, then caching it might be worthwhile. Instead of going to a
- file or database on every hit, you simply go to the cache and grab
- the latest version from there. This is \textbf{\emph{very}} fast,
- at the cost of some memory.
- If you know exactly what you want to cache, the \emph{Yolk.Cache.Discrete\_Keys}
- package might be just what you need.
- \subsection{The generic formal parameters}
- These are:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- generic
- type Key_Type is (<>);
- type Element_Type is private;
- Max_Element_Age : Duration := 3600.0;
- package Yolk.Cache.Discrete_Keys is
- ...
- \end{lstlisting}
- %
- \end{minipage}
- The \emph{Max\_Element\_Age} defaults to one hour. You should obviously
- set this to whatever suits your needs. This timer is used for all
- content in the cache. You cannot set this individually for each element.
- \subsection{Instantiation}
- If for example we have two different sets of data (Foo and Bar) that
- are expensive to build, we can instantiate a \emph{Discrete\_Keys}
- package to handle this:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- type Cache_Keys is (Foo, Bar);
- package My_Cache is new Yolk.Cache.Discrete_Keys
- (Key_Type => Cache_Keys,
- Element_Type => Unbounded_String);
- \end{lstlisting}
- %
- \end{minipage}
- And that is all. We now have a \emph{My\_Cache} object that can hold
- two objects: \emph{Foo} and \emph{Bar}. These are of the type \emph{Unbounded\_String}
- and they have a \emph{Max\_Element\_Age} of 3600.0 seconds.
- \subsection{Writing to the cache}
- Before we can read something from the cache, we must first write something
- to it:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- declare
- Foo_Value : Unbounded_String := To_Unbounded_String ("Foo");
- begin
- My_Cache.Write (Key => Foo,
- Value => Foo_Value);
- end;
- \end{lstlisting}
- %
- \end{minipage}
- That is all it takes: {}``Foo'' is now safely tucked away in the
- \emph{My\_Cache} object, and will be so for 3600.0 seconds. Calling
- \emph{Write} with the \emph{Foo }key will always overwrite earlier
- written \emph{Foo} elements, no matter their age.
- \subsection{Reading from the cache}
- A cache obviously only makes sense if you intend to read from it.
- In our case we want to get our hands on the previously written {}``Foo''
- value:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- declare
- Valid : Boolean := False;
- Value : Unbounded_String;
- begin
- My_Cache.Read (Key => Foo,
- Is_Valid => Valid,
- Value => Value);
- if Valid then
- -- do something interesting with the data
- else
- -- the Foo data is invalid.
- end if;
- end;
- \end{lstlisting}
- %
- \end{minipage}
- In order for an element to be valid (the\emph{ Is\_Valid} parameter
- is true), it must:
- \begin{enumerate}
- \item have been added to the cache in the first place
- \item be younger than \emph{Max\_Element\_Age}
- \end{enumerate}
- If \emph{Is\_Valid} is \emph{False}, then \emph{Value} is undefined.
- Note that if \emph{Is\_Valid} is \emph{False} then \emph{Key} is removed
- from the cache, if it exists.
- \subsection{Checking if a key is valid}
- If you need to check whether a specific key exists in the cache and
- is valid, then you must use the \emph{Is\_Valid} function.
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- if My_Cache.Is_Valid (Foo) then
- -- Foo is good!
- else
- -- Foo is bad!
- end if;
- \end{lstlisting}
- %
- \end{minipage}
- This follows the same rules as the \emph{Is\_Valid} parameter for
- the \emph{Read} procedure.
- \subsection{Clearing keys and the entire cache}
- For clearing of keys and the entire cache we have, naturally, two
- \emph{Clear} procedures:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- -- First we clear the Foo key
- My_Cache.Clear (Key => Foo);
- -- And then we clear the entire cache
- My_Cache.Clear;
- \end{lstlisting}
- %
- \end{minipage}
- And that's all it takes.
- \subsection{Cleanup - Getting rid of stale elements}
- Calling Cleanup will delete all stale elements from the cache:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- My_Cache.Cleanup;
- \end{lstlisting}
- %
- \end{minipage}
- Note that this is potentially a very expensive operation if the cache
- is large, as the entire cache is iterated and every element tested
- for its age. Use with care.
- \section{Yolk.Cache.String\_Keys}
- This package is almost similar to the \emph{Yolk.Cache.Discrete\_Keys}
- package. The biggest difference is that where the \emph{Discrete\_Keys}
- cache package requires that you define a type for the keys, this package
- use regular \emph{String} as keys.
- The implications of this difference between the two cache packages
- are subtle. Both have the same \emph{Read}, \emph{Write}, \emph{Is\_Valid}
- and \emph{Clear} procedures and functions, so in that sense the two
- packages are the same. The biggest difference lies in the available
- generic formal parameters and the functionality of the \emph{Cleanup}
- procedure.
- \subsection{The generic formal parameters}
- These are:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- generic
- type Element_Type is private;
- Cleanup_Size : Positive := 200;
- Cleanup_On_Write : Boolean := True;
- Max_Element_Age : Duration := 3600.0;
- Reserved_Capacity : Positive := 100;
- package Yolk.Cache.Discrete_Keys is
- ...
- \end{lstlisting}
- %
- \end{minipage}
- When the amount of elements in the cache >= \emph{Cleanup\_Size},
- then the \emph{Cleanup} procedure is called by \emph{Write}, if \emph{Cleanup\_On\_Write}
- is set to Boolean \emph{True}. \emph{Cleanup\_Size} is a sort of failsafe
- for this cache package. Since we can't know for sure what is being
- added (we don't know the keys beforehand), we need to make sure it
- doesn't gobble up all available resources. Set this number high enough
- that it'll never tricker under normal circumstances, but low enough
- that it'll prevent resource exhaustion in case of errors.
- The \emph{Max\_Element\_Age} defaults to one hour. You should obviously
- set this to whatever suits your needs. This timer is used for all
- content in the cache. You cannot set this individually for each element.
- \emph{Reserved\_Capacity} should be set as close as possible to the
- expected final size of the cache. If your best guestimate is 200 elements
- in the cache, then set this to 200. Note that this setting has no
- bearing on the actual size of the cache. The cache will happily grow
- beyond the \emph{Reserved\_Capacity} value.
- \subsection{Instantiation}
- Instantiating \emph{String\_Keys} is done like this:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- package My_Cache is new Yolk.Cache.String_Keys
- (Element_Type => Unbounded_String,
- Reserved_Capacity => 200);
- \end{lstlisting}
- %
- \end{minipage}
- And that is all. We now have a \emph{My\_Cache} object that can hold
- objects of the type \emph{Unbounded\_String}, all of which have a
- \emph{Max\_Element\_Age} of 3600.0 seconds. Also we've told the cache
- to set aside at least 200 positions for content.
- \subsection{Writing to the cache}
- Before we can read something from the cache, we must first write something
- to it:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- declare
- Value : Unbounded_String := To_Unbounded_String ("42");
- begin
- My_Cache.Write (Key => "Foo",
- Value => Value);
- end;
- \end{lstlisting}
- %
- \end{minipage}
- {}``42'' is now safely tucked away in the \emph{My\_Cache} object
- under the key {}``Foo'', and will be so for 3600.0 seconds. Calling
- \emph{Write} with the {}``Foo''\emph{ }String will always overwrite
- earlier written {}``Foo'' elements, no matter their age.
- \subsection{Reading from the cache}
- A cache obviously only makes sense if you intend to read from it.
- In our case we want to get our hands on the previously written {}``Foo''
- value:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- declare
- Valid : Boolean := False;
- Value : Unbounded_String;
- begin
- My_Cache.Read (Key => "Foo",
- Is_Valid => Valid,
- Value => Value);
- if Valid then
- -- do something interesting with the data
- else
- -- the Foo data is invalid.
- end if;
- end;
- \end{lstlisting}
- %
- \end{minipage}
- In order for an element to be valid (the\emph{ Is\_Valid} parameter
- is true), it must:
- \begin{enumerate}
- \item have been added to the cache in the first place
- \item be younger than \emph{Max\_Element\_Age}
- \end{enumerate}
- If \emph{Is\_Valid} is \emph{False}, then \emph{Value} contains undefined
- garbage. Note that if \emph{Is\_Valid} is \emph{False} then \emph{Key}
- is removed from the cache, if it exists.
- \subsection{Checking if a key is valid}
- If you need to check whether a specific key exists in the cache and
- is valid, then you need to use the \emph{Is\_Valid} function.
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- if My_Cache.Is_Valid ("Foo") then
- -- Foo is good!
- else
- -- Foo is bad!
- end if;
- \end{lstlisting}
- %
- \end{minipage}
- This follows the same rules as the \emph{Is\_Valid} parameter for
- the \emph{Read} procedure.
- \subsection{Clearing keys and the entire cache}
- For clearing of keys and the entire cache we have, naturally, two
- \emph{Clear} procedures:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- -- First we clear the Foo key
- My_Cache.Clear (Key => "Foo");
- -- And then we clear the entire cache
- My_Cache.Clear;
- \end{lstlisting}
- %
- \end{minipage}
- \subsection{How much is in there?}
- With the \emph{Discrete\_Keys} cache we obviously always know the
- exact amount of keys available, since we've defined the keys ourselves.
- This is not the case with the \emph{String\_Keys} cache, where any
- \emph{String} can be a key. If we need to know how many elements that
- are currently in the cache, we call the \emph{Length} function:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- if My_Cache.Length > 1000 then
- -- Woa! Lots of stuff in the cache..
- end if;
- \end{lstlisting}
- %
- \end{minipage}
- Note that \emph{Length} count both valid and invalid elements.
- \subsection{Cleanup - Keeping cache size in check}
- if \emph{Cleanup\_On\_Write} is \emph{True}, then \emph{Cleanup} is
- called by \emph{Write }whenever the size of the cache reach \emph{Cleanup\_Size}.
- It is of course also possible to call it manually:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- if My_Cache.Length > 1000 then
- My_Cache.Cleanup;
- end if;
- \end{lstlisting}
- %
- \end{minipage}
- If you've set \emph{Cleanup\_On\_Write} to Boolean \emph{False} and
- the String keys are coming from outside sources, then you really should
- make sure you call \emph{Cleanup} on a regular basis.
- \section{Yolk.Command\_Line}
- This package enables you to fetch the value of a given commandline
- parameter using the \emph{Get} function:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- function Get
- (Parameter : in String;
- Default : in String := "")
- return String;
- \end{lstlisting}
- %
- \end{minipage}
- If \emph{Parameter} is found \emph{Get} will return the value immediately
- following \emph{Parameter.} If \emph{Parameter} isn't found \emph{Default}
- is returned.
- \section{Yolk.Config\_File\_Parser}
- This package enables you to access KEY/VALUE pairs in configuration
- files that are written in the style:
- \begin{lyxcode}
- \#~This~is~a~comment
- -{}-~This~is~also~a~comment
- KEY~VALUE
- \end{lyxcode}
- Keys are case-insensitive, so \emph{FOO}, \emph{foo} and \emph{fOo}
- are all the same.\emph{ }Blank lines and comments are ignored and
- so is pre/postfixed whitespace. It is not necessary to quote values
- that contain whitespace, to this:
- \begin{lyxcode}
- KEY~some~value~with~whitespace
- \end{lyxcode}
- is perfectly valid, and will return {}``\emph{some value with whitespace}''
- when calling \emph{Get (KEY)}. If VALUE is \emph{Boolean} \emph{True}
- or \emph{False} (case-insensitive), then the KEY can be returned as
- a \emph{String} or a \emph{Boolean}, depending on the target type.
- If the target type does not match the VALUE and no sensible conversion
- can be made, then a \emph{Conversion\_Error} exception is raised.
- No dummy values are returned at any time.
- To clear a default value, simply add the key to the configuration
- file, with no value set.
- \subsection{The generic formal parameters}
- These are:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- generic
- use Ada.Strings.Unbounded;
- type Key_Type is (<>);
- type Defaults_Array_Type is array (Key_Type) of Unbounded_String;
- Defaults : in Defaults_Array_Type;
- Config_File : in String;
- package Yolk.Config_File_Parser is
- ...
- \end{lstlisting}
- %
- \end{minipage}
- \emph{Config\_File} is of course the name and location of the configuration
- file.
- \subsection{Exceptions}
- There are 3 different exceptions that can be raised by the \emph{Yolk.Config\_File\_Parser}
- package. These are:
- \begin{itemize}
- \item \emph{Unknown\_Key}. This is raised if an unknown key has been found
- in the configuration file given when instantiating the package or
- when \emph{Load\_File} is called.
- \item \emph{Cannot\_Open\_Config\_File}. This is raised when \emph{Config\_File}
- cannot be read.
- \item \emph{Conversion\_Error}. This is raised when a value cannot be converted
- to the target type, ie. the value {}``42'' to a \emph{Boolean}.
- \end{itemize}
- \subsection{Instantiation}
- \emph{Yolk.Config\_File\_Parser} is a generic package, so in order
- to use it, you have to instantiate it, like this:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- package My_Configuration is
- type Keys is (Foo, Bar);
- type Defaults_Array is array (Keys) of Unbounded_String;
- Default_Values : constant Defaults_Array :=
- (Foo => To_Unbounded_String ("some foo"),
- Bar => To_Unbounded_String ("some bar"));
-
- package Config is new Yolk.Config_File_Parser
- (Key_Type => Keys,
- Defaults_Array_Type => Defaults_Array,
- Defaults => Default_Value,
- Config_File => "config.ini");
- end My_Configuration;
- \end{lstlisting}
- %
- \end{minipage}
- Here we instantiate the \emph{Config} package with \emph{config.ini}
- as the configuration file. This means that KEY/VALUE pairs found in
- this file will overwrite the default values set in the \emph{Default\_Values}
- array. Setting a default value to \emph{Null\_Unbounded\_String} means
- the value is empty.
- Note that the \emph{config.ini} file does not have to contain all
- the valid keys. It is perfectly fine to only add those keys that have
- non-default values to the configuration file.
- \subsection{Re-loading configuration files}
- With the \emph{Load\_File} procedure you can re-load a new configuration
- file into your \emph{Config} package:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- My_Configuration.Config.Load_File ("new_config.ini");
- \end{lstlisting}
- %
- \end{minipage}
- Now the KEY/VALUE pairs of \emph{new\_config.ini} will overwrite the
- ones originally found in the \emph{config.ini} file the package was
- instantiated with. You can do this as many times as you like. Note
- that you cannot change what KEY's are valid, so if the \emph{new\_config.ini}
- file contains unknown keys, \emph{Load\_File} will raise the \emph{Unknown\_Key}
- exception.
- \subsection{Getting values}
- With instantiation and loading of configuration files out of the way,
- it is now time to get to the configuration values. To get the value
- of the \emph{Foo} key, you do:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- My_Configuration.Config.Get (Foo);
- \end{lstlisting}
- %
- \end{minipage}
- There are Get functions for the following types:
- \begin{itemize}
- \item \emph{Boolean}
- \item \emph{Duration}
- \item \emph{Float}
- \item \emph{Integer}
- \item \emph{String}
- \item \emph{Unbounded\_String}
- \end{itemize}
- Empty keys simply return an empty \emph{String} or a \emph{Null\_Unbounded\_String},
- depending on the target type. If a key is empty and the target type
- is not a \emph{String} or an \emph{Unbounded\_String}, then the \emph{Conversion\_Error}
- exception is raised.
- \subsection{Checking if a KEY has a VALUE}
- You can check if a key has a value with the \emph{Has\_Value} function:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- if Has_Value (Foo) then
- Put_Line ("Foo has a value");
- end if;
- \end{lstlisting}
- %
- \end{minipage}
- Basically all this function does is return \emph{Boolean} \emph{True}
- if the value of the given key is not a \emph{Null\_Unbounded\_String}.
- \section{Yolk.Configuration}
- This package is a bit of an oddball, as all it does is instantiate
- the \emph{Yolk.Config\_File\_Parser} generic with the default AWS
- and Yolk configuration values. This is used by Yolk internally, but
- also by the AWS component of your application. The instantiation looks
- like this:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- package Config is new Config_File_Parser
- (Key_Type => Keys,
- Defaults_Array_Type => Defaults_Array,
- Defaults => Default_Values,
- Config_File => Config_File);
- \end{lstlisting}
- %
- \end{minipage}
- The \emph{Config\_File} function call return either the default Yolk
- configuration file (\emph{configuration/config.ini}) or a user specified
- configuration file given by the \emph{--yolk-config-file} command
- line argument, so\emph{ }starting for example the Yolk demo like this:
- \begin{lyxcode}
- ./yolk\_demo~-{}-yolk-config-file~/etc/yolk-config.ini
- \end{lyxcode}
- will force the demo to look for the \emph{/etc/yolk-config.ini} configuration
- file.
- There's a fully commented \emph{config.ini.dist} file available in
- the \emph{extras/} directory. I recommend taking a look at the Yolk
- demo application to see how the \emph{Yolk.Configuration} package
- is used.
- \subsection{Get the AWS specific configuration settings}
- On some occassions it might be necessary to get the AWS configuration
- object. This can easily be accomplished by calling the \emph{Get\_AWS\_Configuration}
- function:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- AWS_Config : constant AWS.Config.Object :=
- Yolk.Configuration.Get_AWS_Configuration;
- \end{lstlisting}
- %
- \end{minipage}
- \section{Yolk.Email}
- Using \emph{Yolk.Email} and the child package \emph{Yolk.Email.Composer}
- you can build and send more or less any kind of email:
- \begin{itemize}
- \item Plain text
- \item Multipart/Alternative
- \item Multipart/Mixed
- \end{itemize}
- The package supports adding multiple SMTP servers, meaning you can
- add as many as you need, and the email will then be send via the first
- one that accepts it.
- The \emph{Yolk.Email} package define 4 exceptions and 3 types. The
- facilities for actually constructing and sending the email are found
- in \emph{Yolk.Email.Composer}.
- \subsection{Exceptions}
- These are:
- \begin{itemize}
- \item \emph{Attachment\_File\_Not\_Found}. Is raised if a file attachment
- is not found at the given path.
- \item \emph{No\_Address\_Set}. Is raised if the address component of a To,
- Reply-To, From, Bcc/Cc header is missing.
- \item \emph{No\_Sender\_Set\_With\_Multiple\_From}. Is raised when an email
- contains multiple From headers but no Sender header, as per RFC-5322,
- 3.6.2. http://tools.ietf.org/html/rfc5322
- \item \emph{No\_SMTP\_Host\_Set}. Is raised if the SMTP host list is empty,
- ie. no SMTP host has been set for sending the email.
- \end{itemize}
- \subsection{The Yolk.Email types}
- When using \emph{Yolk.Email.Composer} to build and send emails, three
- types declared in \emph{Yolk.Email} are central:
- \begin{enumerate}
- \item \emph{Character\_Set}
- \item \emph{Recipient\_Kind}
- \item \emph{Structure}
- \end{enumerate}
- The \emph{Character\_Set} type define what character set is used when
- data is added to an email \emph{Structure} object. For example looking
- at the \emph{Yolk.Email.Composer.Add\_From} procedure, we see that
- the \emph{Charset} parameter defaults to \emph{US\_ASCII}:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Add_From
- (ES : in out Structure;
- Address : in String;
- Name : in String := "";
- Charset : in Character_Set := US_ASCII);
- \end{lstlisting}
- %
- \end{minipage}
- This does not mean that \emph{Yolk.Email.Composer.Add\_From} will
- encode \emph{Name} as \emph{US\_ASCII}, instead it means that the
- data given in \emph{Name} already is \emph{US\_ASCII}. So if \emph{Name}
- had contained an ISO-8859-1 encoded \emph{String}, then the call would've
- looked like this:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- declare
- use Yolk.Email;
- Email : Structure;
- begin
- Composer.Add_From
- (ES => Email,
- Address => "alice@domain.tld",
- Name => "Alice",
- Charset => ISO_8859_1);
- end;
- \end{lstlisting}
- %
- \end{minipage}
- In this case you will end up with a From header looking like this:
- \begin{lyxcode}
- From:~=?ISO-8859-1?Q?Alice?=~<alice@domain.tld>
- \end{lyxcode}
- So bear in mind that it is your responsibility to ensure that your
- data, and the \emph{Character\_Set} parameter match.
- The \emph{Recipient\_Kind} type define the kind of recipient that
- is being added to an email. If you've worked with email, these three
- should be familiar to you:
- \begin{enumerate}
- \item \emph{Bcc}
- \item \emph{Cc}
- \item \emph{To}
- \end{enumerate}
- When adding recipients to an email \emph{Structure} the default is
- \emph{To}, but since not all recipients are equal, you can change
- the kind of recipient to \emph{Bcc} or \emph{Cc}, according to your
- needs.
- The \emph{Structure} type is at the core of it all. You declare an
- object to be of the \emph{Structure} type, and then you use the \emph{Yolk.Email.Composer}
- facilities to build and send the email.
- \section{Yolk.Email.Composer}
- The actual tools for building and sending an email is found in this
- package. Here are tools for building emails from the ground up and
- there are a few convenience procedures if you just need to send a
- simple email with no bells or whistles.
- I'm not going to go through ever procedure in this package, instead
- I'll show an example on how to build an email from the ground up and
- how to use one of the convenience procedures.
- \subsection{Building and sending an email, the easy way}
- There are two convenience procedures in \emph{Yolk.Email.Composer}
- for sending emails without having to do a whole lot of work/thinking.
- They are both named \emph{Send} and they look like this:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Send
- (ES : in out Structure;
- From_Address : in String;
- From_Name : in String := "";
- To_Address : in String;
- To_Name : in String := "";
- Subject : in String;
- Text_Part : in String;
- SMTP_Server : in String := "localhost";
- SMTP_Port : in Positive := 25;
- Charset : in Character_Set := US_ASCII);
-
- procedure Send
- (ES : in out Structure;
- From_Address : in String;
- From_Name : in String := "";
- To_Address : in String;
- To_Name : in String := "";
- Subject : in String;
- Text_Part : in String;
- HTML_Part : in String;
- SMTP_Server : in String := "localhost";
- SMTP_Port : in Positive := 25;
- Charset : in Character_Set := US_ASCII);
- \end{lstlisting}
- %
- \end{minipage}
- As you can see, the only difference between these two is that the
- first one sends plain text emails, while the second one sends \emph{multipart/alternative}
- with both plain text and HTML parts. Usage is as simple as:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- declare
- use Yolk.Email;
- Email : Structure;
- begin
- Composer.Send (ES => Email,
- From_Address => "alice@domain.tld",
- From_Name => "Alice",
- To_Address => "bob@domain.tld",
- To_Name => "Bob",
- Subject => "Is this thing on?",
- Text_Part => "Hey you!",
- Charset => ISO_8859_1);
-
- if Composer.Is_Send (Email) then
- -- Success!
- else
- -- Failure!
- end if;
- end;
- \end{lstlisting}
- %
- \end{minipage}
- It is possible, and allowed, to call some of the various other procedures
- prior to calling one of the convenience procedures. If for example
- you want to add a custom header, it can be done like this:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- declare
- use Yolk.Email;
- Email : Structure;
- begin
- Composer.Add_Custom_Header (ES => Email,
- Name => "User-Agent",
- Value => "My User Agent");
- Composer.Send (ES => Email,
- From_Address => "alice@domain.tld",
- From_Name => "Alice",
- To_Address => "bob@domain.tld",
- To_Name => "Bob",
- Subject => "Is this thing on?",
- Text_Part => "Hey you!",
- Charset => ISO_8859_1);
-
- if Composer.Is_Send (Email) then
- -- Success!
- else
- -- Failure!
- end if;
- end;
- \end{lstlisting}
- %
- \end{minipage}
- And with that, the header \emph{User-Agent:} is now added to the email:
- \begin{lyxcode}
- User-Agent:~My~User~Agent
- \end{lyxcode}
- It hardly gets any easier than that. Lets move on and see how the
- above is accomplished the hard way.
- \subsection{Building and sending email, the hard way}
- It is possible to build an email from the ground up, which obviously
- allows for a more fine grained control over what is added. It is also
- a bit more complicated, but not much. Lets try and mimick the easy
- examples, the {}``hard'' way:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- declare
- use Yolk.Email;
- Email : Structure;
- begin
- Composer.Add_Custom_Header (ES => Email,
- Name => "User-Agent",
- Value => "My User Agent");
- Composer.Add_From (ES => Email,
- Address => "alice@domain.tld",
- Name => "Alice",
- Charset => ISO_8859_1);
- Composer.Add_Recipient (ES => Email,
- Address => "bob@domain.tld",
- Name => "Bob");
-
- Composer.Set_Subject (ES => Email,
- Subject => "Is this thing on?");
- Composer.Set_Text_Part (ES => Email,
- Part => "Hey you!");
- Composer.Add_SMTP_Server (ES => Email,
- Host => "localhost");
-
- Composer.Send (ES => Email);
-
- if Composer.Is_Send (Email) then
- -- Success!
- else
- -- Failure!
- end if;
- end;
- \end{lstlisting}
- %
- \end{minipage}
- Harder yes, but really not all that much more difficult.
- \section{Yolk.Handlers}
- Most web applications will need to handle static content, such as
- PNG, HTML and CSS files. \emph{Yolk.Handlers} helps you accomplish
- that, so you don't have to build your own handlers for these kinds
- of files.
- The following filetypes are supported by \emph{Yolk.Handlers}:
- \begin{itemize}
- \item CSS
- \item GIF
- \item HTML
- \item ICO
- \item JPG
- \item JS
- \item PNG
- \item SVG
- \item XML
- \item XSL
- \end{itemize}
- The filetypes that are textual, are compressed according to the \emph{Yolk.Configuration}
- parameter \emph{Compress\_Static\_Content} which defaults to \emph{False}.
- The regular expressions for identifying these filetypes are also defined
- in \emph{Yolk.Configuration} by the \emph{Handler\_{*}} parameters.
- These regular expressions are registered by the \emph{AWS.Services.Dispatchers.URI.Register\_Regexp}
- procedure.
- There's only one procedure in the \emph{Yolk.Handlers} package:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Set (RH : out AWS.Services.Dispatchers.URI.Handler);
- \end{lstlisting}
- %
- \end{minipage}
- You can see an example on how this is used in the demo file \emph{my\_handlers.adb}.
- There's really very little reason not to use this package for handling
- of static content, but it is of course not mandatory.
- This package makes use of the \emph{Yolk.Static\_Content} package
- for the actual delivery of the content to the user.
- \section{Yolk.Log}
- This package serves two purposes:
- \begin{enumerate}
- \item It contains the two callback procedures used to write AWS logging
- data (access and error) to syslogd.
- \item It creates the SQL, SQL\_Cache, SQL\_Error, SQL\_Select, Alert, Critical,
- Debug, Emergency, Error, Info, Notice and Warning trace handles, and
- activates them according to the values defined in the configuration
- file.
- \end{enumerate}
- Out of the box, a Yolk application requires a running syslogd daemon,
- as all log data is sent to syslogd. If for some reason you don't want
- to use syslogd, you're going to have to hack the \emph{Yolk.Log} package,
- or remove it entirely.
- The two procedures named \emph{AWS\_{*}} are used by the AWS HTTP(S)
- server. These should not be used for anything else - or rather: If
- you use them for anything else, the \emph{Message} given is going
- to be written to syslogd with either the AWS access log label or AWS
- error log label. There's absolutely no harm in this, except it might
- be a bit confusing when reading the log data.
- The \emph{Trace} procedure is the one that you will be using in your
- application. You can send log data to the trace handles defined in
- \emph{Yolk.Log.Trace\_Handles}. All log data is then sent to the syslogd
- daemon using the facilities set in the configuration file for the
- given trace handle.
- Using \emph{Trace} is about as easy as it gets:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- Yolk.Log.Trace (Handle => Error,
- Message => "Secret sauce to Error!");
- \end{lstlisting}
- %
- \end{minipage}
- If you haven't activated a trace handle, then calling \emph{Trace}
- for that handle does nothing, ie. you don't have to remove all your
- \emph{Trace} calls from the code if you don't use them.
- Note that on many systems the Emergency messages are written to console,
- so be cautious about using this specific level, unless you've made
- certain that you can get to the messages.
- \section{Yolk.Not\_Found}
- The job of this package is to return a HTTP 404 status code and an
- accompanying simple \emph{not found} HTML page. It's sole function
- \emph{Generate} is about as simple as they come:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- function Generate
- (Request : in AWS.Status.Data)
- return AWS.Response.Data;
- \end{lstlisting}
- %
- \end{minipage}
- It relies on the template file \emph{demo/exe/templates/system/404.tmpl}
- to generate the generic 404 HTML page, so if you want to use \emph{Yolk.Not\_Found}
- in your own application, then remember to bring along this file. Where
- the \emph{404.tmpl} is placed is defined in the configuration parameter
- \emph{System\_Templates\_Path}.
- Also worth noting is that the \emph{Yolk.Not\_Found.Generate} function
- is used as the default callback in the demo application. This means
- that all requested resources that doesn't match a registered dispatcher,
- is served by \emph{Yolk.Not\_Found.Generate} ie. a 404 is returned.
- See the \emph{demo/src/my\_handlers.adb} file for more information.
- \section{Yolk.Process\_Control}
- With \emph{Yolk.Process\_Control} you get the ability to control your
- application using the SIGINT, SIGPWR and SIGTERM signals. If you give
- your Yolk application the \emph{--pid-file} commandline argument when
- starting it, \emph{Yolk.Process\_Control} will create a PID file on
- the given location, if it is allowed to do so. This PID file will
- also be deleted when the application terminates. Note that the \emph{extras/rc.yolk}
- script handles all this transparently.
- \subsection{Exceptions}
- These are:
- \begin{itemize}
- \item \emph{Cannot\_Create\_PID\_File}. Is raised if the \emph{PID\_File}
- cannot be created, eg. if the application lacks permissions to write
- to the directory where the \emph{PID\_File} is located.
- \item \emph{Cannot\_Delete\_PID\_File}. Is raised if the \emph{PID\_file}
- cannot be deleted, eg. if the application lacks permissions to write
- to the directory where the \emph{PID\_File} is located, or to the
- \emph{PID\_File} itself.
- \item \emph{PID\_File\_Exists}. Is raised when the \emph{PID\_File} already
- exists, ie. the application is already running or it was shutdown
- incorrectly.
- \end{itemize}
- \subsection{Using Yolk.Process\_Control}
- When you use the \emph{Yolk.Process\_Control} package the \emph{Unreserve\_All\_Interrupts}
- pragma is used. This means that depending on the compiler used one
- or more interrupt signals may be affected. In the case of the GNAT
- compiler, this is specifically mentioned in the source of the \emph{Ada.Interrupts.Names}
- package:
- \begin{quote}
- -- The pragma Unreserve\_All\_Interrupts affects the following signal(s):
- -- SIGINT: made available for Ada handler
- \end{quote}
- Since neither SIGPWR or SIGTERM are reserved by the compiler, the
- \emph{Yolk.Process\_Control} package is able to assume control of
- these signals. You can read more about the \href{http://gcc.gnu.org/onlinedocs/gnat_rm/Pragma-Unreserve_005fAll_005fInterrupts.html}{pragma Unreserve\_{}All\_{}Interrupts here}.
- If you compile Yolk with a different compiler than GNAT, then please
- check if one of the affected signals are reserved.
- There are two procedures in the \emph{Yolk.Process\_Control} package:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Stop;
- procedure Wait;
- \end{lstlisting}
- %
- \end{minipage}
- When you call the \emph{Wait} procedure, you basically hang there
- until
- \begin{enumerate}
- \item The \emph{Stop} procedure is called
- \item The application receives a SIGINT, SIGPWR or SIGTERM signal
- \end{enumerate}
- This is quite handy for applications, that need some sort of loop
- to keep them from terminating. You can see an example on how this
- can be done in the \emph{demo/src/yolk\_demo.adb} file.
- When \emph{Wait} is called, subsequent calls to \emph{Wait} are ignored,
- unless a call to \emph{Stop} has been made or the application has
- received one of the SIGINT, SIGPWR or SIGTERM signals. So it's perfectly
- valid to do:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- Wait;
- -- Stop called from somewhere in the app
- -- Do something...
- Wait;
- -- The app receives a SIGINT signal
- -- Do something...
- Wait;
- \end{lstlisting}
- %
- \end{minipage}
- Whether or not this is actually useful I don't know, but it is possible.
- \section{Yolk.Process\_Owner}
- When it is necessary to change the owner of a process, the \emph{Yolk.Process\_Owner}
- package is the solution. Obviously this can also be done when starting
- the application, using various shell tricks, but I find it it much
- cleaner to just let the application handle it by itself.
- \subsection{Exceptions}
- There's only one:
- \begin{enumerate}
- \item \emph{Username\_Does\_Not\_Exist}. This is raised if the given username
- doesn't exist on the system.
- \end{enumerate}
- \subsection{Using Yolk.Process\_Owner}
- There's only a single procedure in this package and its specification
- looks like this:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Set_User
- (Username : in String);
- -- Set the process owner to Username.
- \end{lstlisting}
- %
- \end{minipage}
- Please note that when changing the user ID of the application with
- \emph{Set\_User}, the group ID is changed to the first group the given
- user is a member of.
- Usage is as simple as expected:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- declare
- begin
- Set_User (Username => "billybob");
- exception
- when Username_Does_Not_Exist =>
- -- User is missing. Do something!
- end;
- \end{lstlisting}
- %
- \end{minipage}
- In the file \emph{demo/src/yolk\_demo.adb} you'll find that \emph{Yolk.Process\_Owner.Set\_User}
- is used in conjunction with the \emph{Yolk.Configuration.Yolk\_User}
- parameter.
- \section{Yolk.Server}
- This is a convenience package to handle creating, starting and stopping
- an AWS HTTP server. The biggest drawback to this package is that it
- can only create and manage \emph{one} AWS server.
- Note a potential manual operation when using the \emph{Yolk.Server
- }package : Setting the \emph{Cache-Control} header. This can become
- necessary if you
- \begin{enumerate}
- \item use \emph{Yolk.Server} to create and start your AWS server AND
- \item use the \emph{Yolk.Handlers} package to register dispatchers for static
- content AND
- \item have the \emph{Compress\_Static\_Content} configuration parameter
- set to \emph{True }AND
- \item aren't content with the default \emph{Cache-Control} header
- \end{enumerate}
- In that case you can use the \emph{Yolk.Static\_Content.Set\_Cache\_Options}
- procedure to work your own magic on the \emph{Cache-Control} header
- sent to clients requesting static content. See the Yolk.Static\_Content
- chapter for more information.
- \subsection{Yolk.Server.Create}
- Creating a server is done by calling the \emph{Create} function. This
- function accepts one parameter that should be fairly self-explanatory.
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- type HTTP is tagged limited private;
- function Create
- (Unexpected : in AWS.Exceptions.Unexpected_Exception_Handler)
- return HTTP;
- \end{lstlisting}
- %
- \end{minipage}
- \subsection{Yolk.Server.Start}
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Start
- (WS : in out HTTP;
- Dispatchers : in AWS.Dispatchers.Handler'Class);
- \end{lstlisting}
- %
- \end{minipage}
- This does as expected: Starts the server with\emph{ Dispatchers.}
- When calling \emph{Start} several things happen:
- \begin{enumerate}
- \item If the configuration parameter \emph{Load\_MIME\_Types\_File} is \emph{True}
- then the MIME types file given in \emph{MIME\_Types\_File} is loaded
- into AWS.
- \item If the configuration parameter \emph{Start\_WebSocket\_Servers} is
- \emph{True} then the AWS WebSocket servers are started.
- \item \emph{Yolk.Static\_Content.Static\_Content\_Cache\_Setup} is called
- with its default parameters if the configuration parameter \emph{Compress\_Static\_Content}
- is \emph{True}.
- \item If session support is turned on for the server and the \emph{Session\_Data\_File}
- exists, then the session data is loaded from this file.
- \item The \emph{Yolk.Log.AWS\_Access\_Log\_Writer} procedure is registered
- to handle all AWS access log data if the configuration parameter \emph{AWS\_Access\_Log\_Activate}
- is \emph{True} .
- \item The \emph{Yolk.Log.AWS\_Error\_Log\_Writer} procedure is registered
- to handle all AWS error log data if the configuration parameter \emph{AWS\_Error\_Log\_Activate}
- is \emph{True} .
- \end{enumerate}
- \subsection{Yolk.Server.Stop}
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Stop
- (WS : in out HTTP);
- \end{lstlisting}
- %
- \end{minipage}
- This does as expected: Stops everything that was started when the
- \emph{Yolk.Server.Start} call was made. Note that if sessions support
- is turned on for the server, then the \emph{Dispatchers} are switched
- for a plain \emph{Not Found} dispatcher when \emph{Stop} is called.
- This is done to prevent session tampering while the server is shutting
- down.
- \section{Yolk.Static\_Content}
- Most web applications have a lot of static content, ie. stuff that
- rarely changes. Things like PNG's, HTML, CSS and Javascript. These
- are content types that are common for most websites, so a application
- is going to have to handle these in some way. This is where \emph{Yolk.Static\_Content}
- comes in. Two kinds of files are handled by \emph{Yolk.Static\_Content}:
- \begin{itemize}
- \item Compressable (XML, HTML, CSS, JS and so on)
- \item Non-compressable (PNG, JPG, GIF, ICO and so on)
- \end{itemize}
- It is up to you, the user, to decide whether a specific kind of file
- is compressable or not - the package does not make any such assumptions.
- The difference between the two, is that compressable files are compressed
- prior to delivery, if the clients HTTP request includes a \emph{Accept-Encoding:
- gzip} header. Non-compressable files are simply returned as is. For
- both kinds, a generic 404 is returned if the requested file doesn't
- exist.
- \emph{Yolk.Static\_Content} is affected by five configuration settings:
- \begin{itemize}
- \item Compress\_Static\_Content
- \item Compress\_Static\_Content\_Minimum\_File\_Size
- \item Compressed\_Static\_Content\_Cache
- \item Compressed\_Static\_Content\_Max\_Age
- \item WWW\_Root
- \end{itemize}
- You should carefully read the \emph{demo/exe/configuration/config.ini}
- file for information on what exactly these do.
- \subsection{Yolk.Static\_Content.Static\_Content\_Cache\_Setup}
- The configuration parameter \emph{Compressed\_Static\_Content\_Cache}
- defines where the compressed version of the static content is saved.
- When your application is started, this directory may or may not exist,
- and it may or may not contain various compressed files. To make sure
- that the directory exists and is empty, you should call the \emph{Static\_Content\_Cache\_Setup}
- procedure:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Static_Content_Cache_Setup
- (No_Cache : in Boolean := False;
- No_Store : in Boolean := False;
- No_Transform : in Boolean := False;
- Max_Age : in AWS.Messages.Delta_Seconds := 86400;
- S_Max_Age : in AWS.Messages.Delta_Seconds :=
- AWS.Messages.Unset;
- Public : in Boolean := False;
- Must_Revalidate : in Boolean := True;
- Proxy_Revalidate : in Boolean := False);
- \end{lstlisting}
- %
- \end{minipage}
- This procedure creates the \emph{Compressed\_Static\_Content\_Cache}
- directory if it doesn't already exists and if it exists, it deletes
- everything in it. So basically you're left with an empty directory
- after a call to this procedure.
- The parameters defines the content of the \emph{Cache-Control} header
- sent to the user agent when a request for static content is made.
- The default parameters are fairly sane, and will result in a cache
- header looking like this:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- Cache-Control: max-age=86400, must-revalidate
- \end{lstlisting}
- %
- \end{minipage}
- Read the \href{http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html\#sec14.9}{HTTP/1.1 Cache-Control header definition}
- for more information on what the various settings do.
- If you use \emph{Yolk.Server} to create and start your AWS server,
- then this called is made automatically with it's default parameters.
- If you don't use \emph{Yolk.Server} and you use the \emph{Yolk.Static\_Content}
- package to serve static content, then you must call this procedure
- before starting the AWS server. Calling it repeatedly will simply
- wipe out the compressed cache directory and reset the \emph{Control\_Cache}
- header according to the given parameters.
- \subsection{Yolk.Static\_Content.Compressable}
- If your application contains a bunch of compressable files of significant
- size, you can save a lot of bandwidth by using the \emph{Compressable}
- function to serve them:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- function Compressable
- (Request : in AWS.Status.Data)
- return AWS.Response.Data;
- \end{lstlisting}
- %
- \end{minipage}
- A natural place to call this function would be where you define your
- content handlers, as seen in this, slightly altered, excerpt from
- the \emph{Yolk.Handlers} package:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- declare
- package SC renames Yolk.Static_Content;
- Resource_Handlers : AWS.Services.Dispatchers.URI.Handler;
- begin
- AWS.Services.Dispatchers.URI.Register_Regexp
- (Dispatcher => Resource_Handlers,
- URI => "\.css$",
- Action => Create (Callback => SC.Compressable'Access));
- AWS.Services.Dispatchers.URI.Register_Regexp
- (Dispatcher => Resource_Handlers,
- URI => "\.html$",
- Action => Create (Callback => SC.Compressable'Access));
- end;
- \end{lstlisting}
- %
- \end{minipage}
- Here you can see that we've defined some content handlers for CSS
- and HTML files based on a few simple regular expressions, and whenever
- a resource is requested that matches one of these, the corresponding
- \emph{Action} callback is called, which in this example is the \emph{Compressable}
- function. The following steps are then taken:
- \begin{enumerate}
- \item Does the requested resource exist and is it an ordinary file?
- \begin{enumerate}
- \item If no, then return a 404 message
- \item if yes, then proceed to 2
- \end{enumerate}
- \item Does the client support compressed content?
- \begin{enumerate}
- \item If no, then return the requested resource un-compressed
- \item if yes, then proceed to 3
- \end{enumerate}
- \item Is there a compressed version of the resource available on disk?
- \begin{enumerate}
- \item if no, then make one, cache it for future use, and return it
- \item If yes, then proceed to 4
- \end{enumerate}
- \item Is the age of the compressed file <= Compressed\_Max\_Age?
- \begin{enumerate}
- \item If no, then delete the current file, build a new one, cache it and
- return it
- \item If yes, then return it
- \end{enumerate}
- \end{enumerate}
- And that's really all there is to it. Note that \emph{Compressable}
- always looks for requested content in the \emph{WWW\_Root} directory,
- so if the user requests the file \emph{/css/index.css}, then the path
- is going to be:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- WWW_Root & "/css/index.ss";
- \end{lstlisting}
- %
- \end{minipage}
- Using the default configuration value for \emph{WWW\_Root}, we'll
- end up with the path:
- \begin{lyxcode}
- static\_content/css/index.css
- \end{lyxcode}
- The compressed version of \emph{index.css} is saved as:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- Compressed_Static_Content_Cache & "/css/index.css" & ".gz";
- \end{lstlisting}
- %
- \end{minipage}
- Using the default configuration value for \emph{Compressed\_Static\_Content\_Cache},
- we'll end up with the path:
- \begin{lyxcode}
- static\_content/compressed\_cache/css/index.css.gz
- \end{lyxcode}
- In these two cases the paths are relative to the executable, but you
- can of course also define \emph{WWW\_Root} and \emph{Compressed\_Static\_Content\_Cache}
- as absolute paths in the configuration file.
- \subsection{Yolk.Static\_Content.Non\_Compressable}
- A lot of static content really doesn't benefit from any further compression.
- This is the case for PNG files, JPEG files and a whole lot of other
- kinds of files. Static content that has already been compressed, should
- be handled by the \emph{Non\_Compressable} function:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- function Non_Compressable
- (Request : in AWS.Status.Data)
- return AWS.Response.Data;
- \end{lstlisting}
- %
- \end{minipage}
- A call to \emph{Non\_Compressable} is much simpler compared to a call
- to it's sibling function \emph{Compressable}:
- \begin{enumerate}
- \item Does the requested resource exist and is it an ordinary file?
- \begin{enumerate}
- \item If no, then return a 404 message
- \item if yes, then return the file
- \end{enumerate}
- \end{enumerate}
- And that's it. Either the resource is there, or it isn't. If the requested
- resource is \emph{/images/foo.png}, then the \emph{Non\_Compressable}
- function searches for the resource in:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- WWW_Root & "/images/foo.png";
- \end{lstlisting}
- %
- \end{minipage}
- Using the default configuration value for \emph{WWW\_Root}, we'll
- end up with the path:
- \begin{lyxcode}
- static\_content/images/foo.png
- \end{lyxcode}
- Just as with \emph{Compressable} a natural place to use \emph{Non\_Compressable}
- is where you define you content handlers, but it can obviously be
- used wherever your application handles requests for static content.
- \subsection{Yolk.Static.Set\_Cache\_Options}
- You can alter the \emph{Cache-Control} header sent to clients requesting
- static content with a call to \emph{Set\_Cache\_Options}\@. This
- is especially handy if you use the \emph{Yolk.Server} package to create
- and start your server, since the initial call to \emph{Static\_Content\_Cache\_Setup}
- is hidden you're forced to live with the default values given in the
- \emph{Static\_Content\_Cache\_Setup} call, resulting in a \emph{Cache-Control}
- header looking like this:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- Cache-Control: max-age=86400, must-revalidate
- \end{lstlisting}
- %
- \end{minipage}
- If this is not what you want, you can use \emph{Set\_Cache\_Options}
- to change it:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Set_Cache_Options
- (No_Cache : in Boolean := False;
- No_Store : in Boolean := False;
- No_Transform : in Boolean := False;
- Max_Age : in AWS.Messages.Delta_Seconds := 86400;
- S_Max_Age : in AWS.Messages.Delta_Seconds :=
- AWS.Messages.Unset;
- Public : in Boolean := False;
- Must_Revalidate : in Boolean := True;
- Proxy_Revalidate : in Boolean := False);
- \end{lstlisting}
- %
- \end{minipage}
- This MUST be called immediately after having called \emph{Yolk.Server.Start},
- since the call to \emph{Static\_Content\_Cache\_Setup} in \emph{Start}
- will overwrite the cache options.
- \section{Yolk.Syndication}
- The Atom Syndication format (\href{http://tools.ietf.org/html/rfc4287}{RFC4287})
- is an XML-based document format that describes lists of related information
- known as \textquotedbl{}feeds\textquotedbl{}. Atom documents are used
- by many web applications as a means of publishing information to users.
- It's not a complicated format, but it does require a bit of work to
- construct a proper Atom feed by hand, and since I try my best to avoid
- work, I made the \emph{Yolk.Syndication} package. This package makes
- it {}``easy'' to put together an Atom feed document, and have it
- delivered as a string or an XML/Ada DOM object.
- \emph{Yolk.Syndication} helps you construct the Atom XML - it does
- not check that the resulting XML is valid Atom XML, ie. that the Atom
- rules have been followed, so if the Atom specification says that
- \begin{quote}
- atom:feed elements MUST contain exactly one atom:id element.
- \end{quote}
- then it is your job to make sure that your Atom feed has exactly one
- such element. So before venturing into the realm of Atom, it's probably
- a good idea to read \href{http://tools.ietf.org/html/rfc4287}{RFC4287}
- for a good understanding of the requirements for this document format.
- A basic example of how to build an Atom feed can be found in the Yolk
- demo application.
- There are two packages in the \emph{Yolk.Syndication} hierarchy:
- \begin{itemize}
- \item \emph{Yolk.Syndication} - Here the necessary types and exceptions
- are defined.
- \item \emph{Yolk.Syndication.Writer} - Here the functions and procedures
- for actually creating an Atom feed are defined.
- \end{itemize}
- When time permits, I'll add a \emph{Yolk.Syndication.Reader} package
- for extraction of data from an Atom feed.
- \subsection{Exceptions}
- There's one exception in this package:
- \begin{itemize}
- \item \emph{Not\_Valid\_XML}. Is raised when some Xhtml content is not valid
- XML. This exception can be raised by all procedures that takes Xhtml
- as content.
- \end{itemize}
- \subsection{The Yolk.Syndication types}
- There are 5 important types in this package:
- \begin{itemize}
- \item \emph{Text\_Kinds}
- \item \emph{Relation\_Kinds}
- \item \emph{Atom\_Entry}
- \item \emph{Atom\_Entry\_Source}
- \item \emph{Atom\_Feed}
- \end{itemize}
- A few of the procedures in \emph{Yolk.Syndication.Writer} has parameters
- of the \emph{Text\_Kinds} type. This identifies the kind of data that
- is being added, with possible values being
- \begin{itemize}
- \item \emph{Text}
- \item \emph{Html}
- \item \emph{Xhtml}
- \end{itemize}
- Hopefully it's obvious what each of these refers to. Procedures that
- have parameters of the \emph{Text\_Kinds} type always add data to
- the feed that can be interpreted as one of these three kinds of text.
- The \emph{Relation\_Kinds} type is used in correlation with links
- that are added to the feed. It identifies how the link relates to
- the current feed/entry. There are 5 possible relations:
- \begin{itemize}
- \item \emph{Alternate}: Signifies that the link points to an alternate version
- of the resource described by the containing element.
- \item \emph{Related}: Signifies that the link points to a resource that
- is related to, but not the same as, the resource described by the
- containing element.
- \item \emph{Self}: Signifies that the link points to a resource that is
- equivalent to the resource described by the containing element. All
- feeds should have one link with a \emph{Self} relation pointing to
- itself.
- \item \emph{Enclosure}: Signifies that the link points to a resource that
- is related to, but not the same as, the resource described by the
- containing element. It also signifies that the resource potentially
- is large in size and might require special handling. If \emph{Enclosure}
- is used, then usually the \emph{Length} parameter is set to hint at
- the size of the resource.
- \item \emph{Via}: Signifies that the resource provided by the containing
- element originates in the URI given by the \emph{Href} parameter of
- the link element.
- \end{itemize}
- Finally we have the most important types:
- \begin{itemize}
- \item \emph{Atom\_Entry}: An entry in a feed.
- \item \emph{Atom\_Entry\_Source}: The origin of an entry.
- \item \emph{Atom\_Feed}: The Atom feed.
- \end{itemize}
- These are core to the functionality of \emph{Yolk.Syndication}, and
- every single procedure and function in the \emph{Yolk.Syndication.Writer}
- package use one or the other. These three types are \emph{private},
- so the only way to declare an object of either one, is by calling
- the \emph{New\_Atom\_Feed}, \emph{New\_Atom\_Entry} or \emph{New\_Atom\_Entry\_Source}
- functions respectively.
- Note that only \emph{Atom\_Feed} is thread safe. The two entry related
- types are not.
- \subsection{Yolk.Syndication.New\_Atom\_Feed}
- This function initialize an \emph{Atom\_Feed} type, and its specification
- looks like this:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- function New_Atom_Feed
- (Base_URI : in String := None;
- Language : in String := None;
- Max_Age : in Duration := 5_616_000.0;
- Max_Entries : in Positive := 100;
- Min_Entries : in Positive := 10)
- return Atom_Feed;
- \end{lstlisting}
- %
- \end{minipage}
- The \emph{Base\_URI} parameter establish a base for resolving relative
- references in the feed. The \emph{Language} parameter indicates the
- natural language used in the feed. \emph{Max\_Age} is a duration that
- determine when an entry in the feed is old enough to be deleted. \emph{Max\_Entries}
- is the amount of entries kept in the feed. If there are more than
- this amount of entries in the feed, then the oldest are deleted until
- the feed contains \emph{Max\_Entries} entries again. \emph{Min\_Entries}
- is the minimum amount of entries that must be present in the feed,
- before we bother deleting entries whose age is > \emph{Max\_Age}.
- If there are less than \emph{Min\_Entries} entries in the feed, then
- we keep even a 100 year old entry.
- What these parameters hints at, is that some automatic maintenance
- is done when using \emph{Yolk.Syndication}, and this is indeed true.
- Usually you do not want a feed to grow forever, and instead of having
- to manually clear away old stuff, \emph{Yolk.Syndication} handles
- all this for you, according to the values given when you instantiate
- an \emph{Atom\_Feed} object using \emph{New\_Atom\_Feed}.
- \subsection{Yolk.Syndication.New\_Atom\_Entry}
- This function initialize an \emph{Atom\_Entry} type, and its specification
- looks like this:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- function New_Atom_Entry
- (Base_URI : in String := None;
- Language : in String := None)
- return Atom_Entry;
- \end{lstlisting}
- %
- \end{minipage}
- As you can see, it's a lot simpler than the \emph{New\_Atom\_Feed}
- function. This is of course because all the automatic maintenance
- related parameters have already been set by they \emph{New\_Atom\_Feed}
- function. All that is left is to define the \emph{Base\_URI} and the
- natural \emph{Language} used by the entry.
- \subsection{Yolk.Syndication.New\_Atom\_Entry\_Source}
- This function initialize an \emph{Atom\_Entry\_Source} type, and its
- specification looks like this:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- function New_Atom_Entry_Source
- (Base_URI : in String := None;
- Language : in String := None)
- return Atom_Entry_Source;
- \end{lstlisting}
- %
- \end{minipage}
- As you can see, this is very similar to the \emph{New\_Atom\_Entry}
- function, since its job is to return an \emph{Atom\_Entry\_Source}
- object, which is basically just an object that describes the origins
- of a feed entry.
- \subsection{Yolk.Syndication.Writer}
- In this package we find all the tools necessary to build the Atom
- XML. There are far too many subprograms in \emph{Yolk.Syndication.Writer}
- to list here, so instead I'll refer you to the source code. All the
- subprograms in this package work on one of the \emph{Atom\_Feed},
- \emph{Atom\_Entry} or \emph{Atom\_Entry\_Source} types, for example
- if you want to set a title on your feed, you'll use the \emph{Set\_Title}
- procedure:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Set_Title
- (Feed : in out Atom_Feed;
- Title : in String;
- Base_URI : in String := None;
- Language : in String := None;
- Title_Kind : in Text_Kinds := Text);
- \end{lstlisting}
- %
- \end{minipage}
- Or if the title is for an entry, then:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Set_Title
- (Entr : in out Atom_Entry;
- Title : in String;
- Base_URI : in String := None;
- Language : in String := None;
- Title_Kind : in Text_Kinds := Text);
- \end{lstlisting}
- %
- \end{minipage}
- Or we could add an author to the feed/entry/entry source:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Add_Author
- (Feed : in out Atom_Feed;
- Name : in String;
- Base_URI : in String := None;
- Email : in String := None;
- Language : in String := None;
- URI : in String := None);
- procedure Add_Author
- (Entr : in out Atom_Entry;
- Name : in String;
- Base_URI : in String := None;
- Email : in String := None;
- Language : in String := None;
- URI : in String := None);
- procedure Add_Author
- (Entry_Source : in out Atom_Entry_Source;
- Name : in String;
- Base_URI : in String := None;
- Email : in String := None;
- Language : in String := None;
- URI : in String := None);
- \end{lstlisting}
- %
- \end{minipage}
- There's actually a hint about the kind of XML element that is being
- produced by these procedures. If the name of the procedure starts
- with \emph{Set\_} then it hints at an XML element of which there's
- only ever one. So \emph{Set\_Title} creates a \emph{<title>Foo</title>}
- element, and if called again, overwrites the previous value, whereas
- if the name of procedure starts with \emph{Add\_} then the Atom specification
- allows for multiples of these, as can be seen with the \emph{Add\_Author}
- procedure. Calling this one creates an \emph{<author>} element, and
- calling it again simply adds one more author to the feed/entry/entry
- source.
- Most of the subprograms in this package deals directly with building
- the Atom XML, but there are a few exceptions, as you will see next.
- \subsection{Counting the amount of entries in a feed}
- If you need to know how many entries that are currently in a feed,
- the you can use the \emph{Yolk.Syndication.Writer.Amount\_Of\_Entries}
- function:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- function Amount_Of_Entries
- (Feed : in Atom_Feed)
- return Natural;
- \end{lstlisting}
- %
- \end{minipage}
- \subsection{Clearing and deleting entries}
- There are two procedures available for clearing and deleting entries,
- one for clearing all entries away, and one for deleting entries based
- on their Id. Lets start with the one that clears out everything:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Clear_Entry_List
- (Feed : in out Atom_Feed);
- \end{lstlisting}
- %
- \end{minipage}
- Calling \emph{Clear\_Entry\_List} deletes every single entry that
- has been added to the \emph{Feed} object so far. A less destructive
- procedure is \emph{Delete\_Entry}:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Delete_Entry
- (Feed : in out Atom_Feed;
- Id : in String);
- \end{lstlisting}
- %
- \end{minipage}
- Using this one, you can delete all entries whose Id is \emph{Id}.
- Note that the match must be exact, so case matters. FOO is not the
- same as foo.
- \subsection{Getting the Atom feed}
- When you've added titles, authors, categories, entries and content
- to your feed, the next step is turning it into XML. This can be done
- in one of two ways:
- \begin{enumerate}
- \item As string XML.
- \item As an XML/Ada DOM XML object.
- \end{enumerate}
- The string XML is obviously for the final audience, whereas the DOM
- XML is useful if you need to do some further work on the feed before
- releasing it on the world. Here they are:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- function Get_XML_DOM
- (Feed : in Atom_Feed)
- return DOM.Core.Document;
- function Get_XML_String
- (Feed : in Atom_Feed;
- Pretty_Print : in Boolean := False)
- return String;
- \end{lstlisting}
- %
- \end{minipage}
- Note that if \emph{Pretty\_Print} is \emph{True} then whitespace is
- going get mangled according to these rules:
- \begin{quote}
- If Pretty\_Print is true, then the XML nodes will be indented so that
- children nodes are to the right of their parents. It is set to False
- by default because its use changes the document (addition or removal
- of whitespaces among other things), which in general has no effect
- for automatic tools reading the document. All whitespaces are modified
- outside of elements containing nothing but text nodes. For text nodes,
- leading and trailing whitespaces are also deleted.
- \end{quote}
- \emph{Get\_XML\_String} relies on the \emph{Write} function from XML/Ada
- to generate its output, and the above quote is taken straight from
- the XML/Ada source comments. It's also worth noting that \emph{Get\_XML\_String}
- and \emph{Get\_XML\_DOM} both are pretty resource-hungry, so it's
- probably best to cache the results for later use, instead of calling
- them on each and every hit.
- \section{Yolk.Utilities}
- This package contains various support functionality.
- \section{Yolk.Whoops}
- This package contains one single procedure: \emph{Unexpected\_Exception\_Handler}.
- I suspect the name gives away exactly what this procedure does. It
- looks like this:
- \begin{minipage}[t]{1\columnwidth}%
- \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
- procedure Unexpected_Exception_Handler
- (E : Ada.Exceptions.Exception_Occurrence;
- Log : in out AWS.Log.Object;
- Error : AWS.Exceptions.Data;
- Answer : in out AWS.Response.Data);
- \end{lstlisting}
- %
- \end{minipage}
- You can use this procedure to catch any and all exceptions you've
- failed to catch in your application, ie. the ones AWS pickup and fail
- to do anything sensible with. When \emph{Unexpected\_Reception\_Handler}
- catch an exception, two things happen:
- \begin{enumerate}
- \item The exception is logged to the \emph{Yolk.Log}.\emph{Error }trace.
- \item A HTTP status code 500 is returned to the user.
- \end{enumerate}
- The template used to create the HTTP code 500 error message is\emph{
- demo/exe/templates/system/500.tmpl}. You can of course change this
- to match the look and feel of your application. The path to the \emph{500.tmpl}
- file is set by the configuration setting \emph{System\_Templates\_Path}.
- You can see an example on how to use this procedure in the file \emph{demo/src/yolk\_demo.adb}.
- \end{document}