PageRenderTime 61ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/docs/yolk.tex

http://github.com/ThomasLocke/yolk
LaTeX | 2095 lines | 1622 code | 410 blank | 63 comment | 0 complexity | bf7c3ec6465512a6b9a77b63782c3d0e MD5 | raw file
Possible License(s): AGPL-1.0
  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. \makeatletter
  17. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands.
  18. \newenvironment{lyxcode}
  19. {\par\begin{list}{}{
  20. \setlength{\rightmargin}{\leftmargin}
  21. \setlength{\listparindent}{0pt}% needed for AMS classes
  22. \raggedright
  23. \setlength{\itemsep}{0pt}
  24. \setlength{\parsep}{0pt}
  25. \normalfont\ttfamily}%
  26. \item[]}
  27. {\end{list}}
  28. \makeatother
  29. \begin{document}
  30. \title{Yolk Manual}
  31. \date{Revised December 11th. 2012}
  32. \maketitle
  33. \newpage{}
  34. \tableofcontents{}
  35. \newpage{}
  36. \part{General Information}
  37. \section{Copyright and License}
  38. This document is copyright (C) 2010-, Thomas Lřcke. You may copy this
  39. document, in whole or in part, in any form or by any means, as is
  40. or with alterations, provided that (1) alterations are clearly marked
  41. as alterations and (2) this copyright notice is included unmodified
  42. in any copy.
  43. Yolk is GPLv3 software. You should have received a copy of the GNU
  44. General Public License and a copy of the GCC Runtime Library Exception
  45. along with this program; see the files COPYING3 and COPYING.RUNTIME
  46. respectively. If not, see \href{http://www.gnu.org/licenses/}{http://www.gnu.org/licenses/}.
  47. \section{What is Yolk?}
  48. Yolk is a collection of packages that aim to help build solid web-applications
  49. using Ada. Yolk itself doesn't do a whole lot that can't be accomplished
  50. simply by using \href{http://libre.adacore.com/libre/tools/aws/}{AWS}
  51. and the \href{http://libre.adacore.com/libre/tools/gnat-component-collection/}{GNAT Component Collection (GNATcoll)},
  52. but it does make the job of building complete web-applications a bit
  53. simpler. Things like changing user for the running application, catching
  54. POSIX signals such as SIGKILL, sending log data to syslogd, adding
  55. basic static content handlers, creating and starting/stopping an AWS
  56. powered HTTP server and building Atom syndication XML are all made
  57. a bit easier with Yolk.
  58. A Yolk application is in reality an AWS application, with some sugar
  59. added, so you're not really building a Yolk web-application, as much
  60. as you're building an AWS web-application. What I'm getting at, is
  61. that you need to understand how to use AWS, in order for Yolk to make
  62. any kind of sense. What you get when using Yolk is the little things
  63. that AWS does not readily provide.
  64. \subsection{The Yolk demo application}
  65. Reading this manual will of course (I hope!) help you understand how
  66. to use Yolk, but please consider taking a closer look at the Yolk
  67. demo application to get a feel for how Yolk is actually used. The
  68. demo is heavily commented, so it should be fairly easy to understand
  69. what's going on. The demo application is also very suitable as a foundation
  70. for other AWS/Yolk applications.
  71. It is much easier to show how to use Yolk, than it is to write down
  72. all possible usage scenarios. With the combination of this manual,
  73. the Yolk source files and the demo application, you should be able
  74. to make full use of the Yolk packages in your own applications.
  75. \subsection{The source code}
  76. The Yolk source code is the best documentation there is. This document
  77. is never going to be as comprehensive as the actual source, so I'll
  78. strongly suggest having the source code available as you read this
  79. document. What you will find in this document are short descriptions
  80. of what a package is meant to do and perhaps small usage examples,
  81. not a complete rundown of every type and procedure in a package.
  82. \subsection{Building and installing Yolk}
  83. See the README and INSTALL files. These are found in the Yolk root
  84. directory.
  85. \subsection{The files Yolk depend upon}
  86. When you read this document and the Yolk source code, you'll notice
  87. that quite a few packages depend on various files being available
  88. at specified locations. This is for example the case with the \emph{Yolk.Whoops}
  89. package that expects its template file to be found at the path \emph{templates/system/500.tmpl}
  90. All such {}``dependencies'' will of course be noted accordingly
  91. as we go along, but instead of forgetting one or more in your own
  92. application, I'd much rather encourage using the demo application
  93. as a foundation for your own applications, since all these fixed paths
  94. and files has been properly added to the demo.
  95. I also recommend compiling and running the demo, to make sure your
  96. Yolk install is working as intended. Just read the \emph{demo/README}
  97. and \emph{demo/INSTALL} files for instructions on how to get it up
  98. and running.
  99. \subsection{The Yolk packages naming}
  100. The Yolk packages are pretty diverse, ranging from process control
  101. to sending email. I've tried naming them as sensibly as possible,
  102. in the hope that the package names alone give away their function.
  103. If I've failed, well, you're just going to have to refer to this document
  104. or take a look at the source for yourself.
  105. \newpage{}
  106. \part{The Yolk Packages}
  107. \section{Yolk}
  108. The Yolk main package currently only contain only a few things: The
  109. Yolk \emph{Version} string, a \emph{Config\_File} function to get
  110. the location of the configuration file and a \emph{PID\_File} function
  111. to get the location of the PID file. These are used in a few places,
  112. for example in the \emph{directory.tmpl} template file (the version
  113. string), in the \emph{Yolk.Configuration} package (the \emph{Config\_File}
  114. function) and in the \emph{Yolk.Process\_Control} package (the \emph{PID\_File}
  115. function).
  116. All Yolk applications accepts two commandline arguments:
  117. \begin{itemize}
  118. \item \emph{--yolk-config-file} : Defines the location of the configuration
  119. file. If empty or not set, then use the default location \emph{configuration/config.ini}.
  120. \item \emph{--pid-file} : Defines the location of the PID file. If empty
  121. or not set, then don't write a PID file. Note that if you use the
  122. \emph{extras/rc.yolk} script to control your application, then this
  123. is handled for you transparently.
  124. \end{itemize}
  125. \section{Yolk.Cache.Discrete\_Keys}
  126. If a piece of data doesn't change very often and it is expensive to
  127. build, then caching it might be worthwhile. Instead of going to a
  128. file or database on every hit, you simply go to the cache and grab
  129. the latest version from there. This is \textbf{\emph{very}} fast,
  130. at the cost of some memory.
  131. If you know exactly what you want to cache, the \emph{Yolk.Cache.Discrete\_Keys}
  132. package might be just what you need.
  133. \subsection{The generic formal parameters}
  134. These are:
  135. \begin{minipage}[t]{1\columnwidth}%
  136. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  137. generic
  138. type Key_Type is (<>);
  139. type Element_Type is private;
  140. Max_Element_Age : Duration := 3600.0;
  141. package Yolk.Cache.Discrete_Keys is
  142. ...
  143. \end{lstlisting}
  144. %
  145. \end{minipage}
  146. The \emph{Max\_Element\_Age} defaults to one hour. You should obviously
  147. set this to whatever suits your needs. This timer is used for all
  148. content in the cache. You cannot set this individually for each element.
  149. \subsection{Instantiation}
  150. If for example we have two different sets of data (Foo and Bar) that
  151. are expensive to build, we can instantiate a \emph{Discrete\_Keys}
  152. package to handle this:
  153. \begin{minipage}[t]{1\columnwidth}%
  154. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  155. type Cache_Keys is (Foo, Bar);
  156. package My_Cache is new Yolk.Cache.Discrete_Keys
  157. (Key_Type => Cache_Keys,
  158. Element_Type => Unbounded_String);
  159. \end{lstlisting}
  160. %
  161. \end{minipage}
  162. And that is all. We now have a \emph{My\_Cache} object that can hold
  163. two objects: \emph{Foo} and \emph{Bar}. These are of the type \emph{Unbounded\_String}
  164. and they have a \emph{Max\_Element\_Age} of 3600.0 seconds.
  165. \subsection{Writing to the cache}
  166. Before we can read something from the cache, we must first write something
  167. to it:
  168. \begin{minipage}[t]{1\columnwidth}%
  169. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  170. declare
  171. Foo_Value : Unbounded_String := To_Unbounded_String ("Foo");
  172. begin
  173. My_Cache.Write (Key => Foo,
  174. Value => Foo_Value);
  175. end;
  176. \end{lstlisting}
  177. %
  178. \end{minipage}
  179. That is all it takes: {}``Foo'' is now safely tucked away in the
  180. \emph{My\_Cache} object, and will be so for 3600.0 seconds. Calling
  181. \emph{Write} with the \emph{Foo }key will always overwrite earlier
  182. written \emph{Foo} elements, no matter their age.
  183. \subsection{Reading from the cache}
  184. A cache obviously only makes sense if you intend to read from it.
  185. In our case we want to get our hands on the previously written {}``Foo''
  186. value:
  187. \begin{minipage}[t]{1\columnwidth}%
  188. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  189. declare
  190. Valid : Boolean := False;
  191. Value : Unbounded_String;
  192. begin
  193. My_Cache.Read (Key => Foo,
  194. Is_Valid => Valid,
  195. Value => Value);
  196. if Valid then
  197. -- do something interesting with the data
  198. else
  199. -- the Foo data is invalid.
  200. end if;
  201. end;
  202. \end{lstlisting}
  203. %
  204. \end{minipage}
  205. In order for an element to be valid (the\emph{ Is\_Valid} parameter
  206. is true), it must:
  207. \begin{enumerate}
  208. \item have been added to the cache in the first place
  209. \item be younger than \emph{Max\_Element\_Age}
  210. \end{enumerate}
  211. If \emph{Is\_Valid} is \emph{False}, then \emph{Value} is undefined.
  212. Note that if \emph{Is\_Valid} is \emph{False} then \emph{Key} is removed
  213. from the cache, if it exists.
  214. \subsection{Checking if a key is valid}
  215. If you need to check whether a specific key exists in the cache and
  216. is valid, then you must use the \emph{Is\_Valid} function.
  217. \begin{minipage}[t]{1\columnwidth}%
  218. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  219. if My_Cache.Is_Valid (Foo) then
  220. -- Foo is good!
  221. else
  222. -- Foo is bad!
  223. end if;
  224. \end{lstlisting}
  225. %
  226. \end{minipage}
  227. This follows the same rules as the \emph{Is\_Valid} parameter for
  228. the \emph{Read} procedure.
  229. \subsection{Clearing keys and the entire cache}
  230. For clearing of keys and the entire cache we have, naturally, two
  231. \emph{Clear} procedures:
  232. \begin{minipage}[t]{1\columnwidth}%
  233. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  234. -- First we clear the Foo key
  235. My_Cache.Clear (Key => Foo);
  236. -- And then we clear the entire cache
  237. My_Cache.Clear;
  238. \end{lstlisting}
  239. %
  240. \end{minipage}
  241. And that's all it takes.
  242. \subsection{Cleanup - Getting rid of stale elements}
  243. Calling Cleanup will delete all stale elements from the cache:
  244. \begin{minipage}[t]{1\columnwidth}%
  245. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  246. My_Cache.Cleanup;
  247. \end{lstlisting}
  248. %
  249. \end{minipage}
  250. Note that this is potentially a very expensive operation if the cache
  251. is large, as the entire cache is iterated and every element tested
  252. for its age. Use with care.
  253. \section{Yolk.Cache.String\_Keys}
  254. This package is almost similar to the \emph{Yolk.Cache.Discrete\_Keys}
  255. package. The biggest difference is that where the \emph{Discrete\_Keys}
  256. cache package requires that you define a type for the keys, this package
  257. use regular \emph{String} as keys.
  258. The implications of this difference between the two cache packages
  259. are subtle. Both have the same \emph{Read}, \emph{Write}, \emph{Is\_Valid}
  260. and \emph{Clear} procedures and functions, so in that sense the two
  261. packages are the same. The biggest difference lies in the available
  262. generic formal parameters and the functionality of the \emph{Cleanup}
  263. procedure.
  264. \subsection{The generic formal parameters}
  265. These are:
  266. \begin{minipage}[t]{1\columnwidth}%
  267. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  268. generic
  269. type Element_Type is private;
  270. Cleanup_Size : Positive := 200;
  271. Cleanup_On_Write : Boolean := True;
  272. Max_Element_Age : Duration := 3600.0;
  273. Reserved_Capacity : Positive := 100;
  274. package Yolk.Cache.Discrete_Keys is
  275. ...
  276. \end{lstlisting}
  277. %
  278. \end{minipage}
  279. When the amount of elements in the cache >= \emph{Cleanup\_Size},
  280. then the \emph{Cleanup} procedure is called by \emph{Write}, if \emph{Cleanup\_On\_Write}
  281. is set to Boolean \emph{True}. \emph{Cleanup\_Size} is a sort of failsafe
  282. for this cache package. Since we can't know for sure what is being
  283. added (we don't know the keys beforehand), we need to make sure it
  284. doesn't gobble up all available resources. Set this number high enough
  285. that it'll never tricker under normal circumstances, but low enough
  286. that it'll prevent resource exhaustion in case of errors.
  287. The \emph{Max\_Element\_Age} defaults to one hour. You should obviously
  288. set this to whatever suits your needs. This timer is used for all
  289. content in the cache. You cannot set this individually for each element.
  290. \emph{Reserved\_Capacity} should be set as close as possible to the
  291. expected final size of the cache. If your best guestimate is 200 elements
  292. in the cache, then set this to 200. Note that this setting has no
  293. bearing on the actual size of the cache. The cache will happily grow
  294. beyond the \emph{Reserved\_Capacity} value.
  295. \subsection{Instantiation}
  296. Instantiating \emph{String\_Keys} is done like this:
  297. \begin{minipage}[t]{1\columnwidth}%
  298. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  299. package My_Cache is new Yolk.Cache.String_Keys
  300. (Element_Type => Unbounded_String,
  301. Reserved_Capacity => 200);
  302. \end{lstlisting}
  303. %
  304. \end{minipage}
  305. And that is all. We now have a \emph{My\_Cache} object that can hold
  306. objects of the type \emph{Unbounded\_String}, all of which have a
  307. \emph{Max\_Element\_Age} of 3600.0 seconds. Also we've told the cache
  308. to set aside at least 200 positions for content.
  309. \subsection{Writing to the cache}
  310. Before we can read something from the cache, we must first write something
  311. to it:
  312. \begin{minipage}[t]{1\columnwidth}%
  313. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  314. declare
  315. Value : Unbounded_String := To_Unbounded_String ("42");
  316. begin
  317. My_Cache.Write (Key => "Foo",
  318. Value => Value);
  319. end;
  320. \end{lstlisting}
  321. %
  322. \end{minipage}
  323. {}``42'' is now safely tucked away in the \emph{My\_Cache} object
  324. under the key {}``Foo'', and will be so for 3600.0 seconds. Calling
  325. \emph{Write} with the {}``Foo''\emph{ }String will always overwrite
  326. earlier written {}``Foo'' elements, no matter their age.
  327. \subsection{Reading from the cache}
  328. A cache obviously only makes sense if you intend to read from it.
  329. In our case we want to get our hands on the previously written {}``Foo''
  330. value:
  331. \begin{minipage}[t]{1\columnwidth}%
  332. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  333. declare
  334. Valid : Boolean := False;
  335. Value : Unbounded_String;
  336. begin
  337. My_Cache.Read (Key => "Foo",
  338. Is_Valid => Valid,
  339. Value => Value);
  340. if Valid then
  341. -- do something interesting with the data
  342. else
  343. -- the Foo data is invalid.
  344. end if;
  345. end;
  346. \end{lstlisting}
  347. %
  348. \end{minipage}
  349. In order for an element to be valid (the\emph{ Is\_Valid} parameter
  350. is true), it must:
  351. \begin{enumerate}
  352. \item have been added to the cache in the first place
  353. \item be younger than \emph{Max\_Element\_Age}
  354. \end{enumerate}
  355. If \emph{Is\_Valid} is \emph{False}, then \emph{Value} contains undefined
  356. garbage. Note that if \emph{Is\_Valid} is \emph{False} then \emph{Key}
  357. is removed from the cache, if it exists.
  358. \subsection{Checking if a key is valid}
  359. If you need to check whether a specific key exists in the cache and
  360. is valid, then you need to use the \emph{Is\_Valid} function.
  361. \begin{minipage}[t]{1\columnwidth}%
  362. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  363. if My_Cache.Is_Valid ("Foo") then
  364. -- Foo is good!
  365. else
  366. -- Foo is bad!
  367. end if;
  368. \end{lstlisting}
  369. %
  370. \end{minipage}
  371. This follows the same rules as the \emph{Is\_Valid} parameter for
  372. the \emph{Read} procedure.
  373. \subsection{Clearing keys and the entire cache}
  374. For clearing of keys and the entire cache we have, naturally, two
  375. \emph{Clear} procedures:
  376. \begin{minipage}[t]{1\columnwidth}%
  377. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  378. -- First we clear the Foo key
  379. My_Cache.Clear (Key => "Foo");
  380. -- And then we clear the entire cache
  381. My_Cache.Clear;
  382. \end{lstlisting}
  383. %
  384. \end{minipage}
  385. \subsection{How much is in there?}
  386. With the \emph{Discrete\_Keys} cache we obviously always know the
  387. exact amount of keys available, since we've defined the keys ourselves.
  388. This is not the case with the \emph{String\_Keys} cache, where any
  389. \emph{String} can be a key. If we need to know how many elements that
  390. are currently in the cache, we call the \emph{Length} function:
  391. \begin{minipage}[t]{1\columnwidth}%
  392. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  393. if My_Cache.Length > 1000 then
  394. -- Woa! Lots of stuff in the cache..
  395. end if;
  396. \end{lstlisting}
  397. %
  398. \end{minipage}
  399. Note that \emph{Length} count both valid and invalid elements.
  400. \subsection{Cleanup - Keeping cache size in check}
  401. if \emph{Cleanup\_On\_Write} is \emph{True}, then \emph{Cleanup} is
  402. called by \emph{Write }whenever the size of the cache reach \emph{Cleanup\_Size}.
  403. It is of course also possible to call it manually:
  404. \begin{minipage}[t]{1\columnwidth}%
  405. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  406. if My_Cache.Length > 1000 then
  407. My_Cache.Cleanup;
  408. end if;
  409. \end{lstlisting}
  410. %
  411. \end{minipage}
  412. If you've set \emph{Cleanup\_On\_Write} to Boolean \emph{False} and
  413. the String keys are coming from outside sources, then you really should
  414. make sure you call \emph{Cleanup} on a regular basis.
  415. \section{Yolk.Command\_Line}
  416. This package enables you to fetch the value of a given commandline
  417. parameter using the \emph{Get} function:
  418. \begin{minipage}[t]{1\columnwidth}%
  419. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  420. function Get
  421. (Parameter : in String;
  422. Default : in String := "")
  423. return String;
  424. \end{lstlisting}
  425. %
  426. \end{minipage}
  427. If \emph{Parameter} is found \emph{Get} will return the value immediately
  428. following \emph{Parameter.} If \emph{Parameter} isn't found \emph{Default}
  429. is returned.
  430. \section{Yolk.Config\_File\_Parser}
  431. This package enables you to access KEY/VALUE pairs in configuration
  432. files that are written in the style:
  433. \begin{lyxcode}
  434. \#~This~is~a~comment
  435. -{}-~This~is~also~a~comment
  436. KEY~VALUE
  437. \end{lyxcode}
  438. Keys are case-insensitive, so \emph{FOO}, \emph{foo} and \emph{fOo}
  439. are all the same.\emph{ }Blank lines and comments are ignored and
  440. so is pre/postfixed whitespace. It is not necessary to quote values
  441. that contain whitespace, to this:
  442. \begin{lyxcode}
  443. KEY~some~value~with~whitespace
  444. \end{lyxcode}
  445. is perfectly valid, and will return {}``\emph{some value with whitespace}''
  446. when calling \emph{Get (KEY)}. If VALUE is \emph{Boolean} \emph{True}
  447. or \emph{False} (case-insensitive), then the KEY can be returned as
  448. a \emph{String} or a \emph{Boolean}, depending on the target type.
  449. If the target type does not match the VALUE and no sensible conversion
  450. can be made, then a \emph{Conversion\_Error} exception is raised.
  451. No dummy values are returned at any time.
  452. To clear a default value, simply add the key to the configuration
  453. file, with no value set.
  454. \subsection{The generic formal parameters}
  455. These are:
  456. \begin{minipage}[t]{1\columnwidth}%
  457. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  458. generic
  459. use Ada.Strings.Unbounded;
  460. type Key_Type is (<>);
  461. type Defaults_Array_Type is array (Key_Type) of Unbounded_String;
  462. Defaults : in Defaults_Array_Type;
  463. Config_File : in String;
  464. package Yolk.Config_File_Parser is
  465. ...
  466. \end{lstlisting}
  467. %
  468. \end{minipage}
  469. \emph{Config\_File} is of course the name and location of the configuration
  470. file.
  471. \subsection{Exceptions}
  472. There are 3 different exceptions that can be raised by the \emph{Yolk.Config\_File\_Parser}
  473. package. These are:
  474. \begin{itemize}
  475. \item \emph{Unknown\_Key}. This is raised if an unknown key has been found
  476. in the configuration file given when instantiating the package or
  477. when \emph{Load\_File} is called.
  478. \item \emph{Cannot\_Open\_Config\_File}. This is raised when \emph{Config\_File}
  479. cannot be read.
  480. \item \emph{Conversion\_Error}. This is raised when a value cannot be converted
  481. to the target type, ie. the value {}``42'' to a \emph{Boolean}.
  482. \end{itemize}
  483. \subsection{Instantiation}
  484. \emph{Yolk.Config\_File\_Parser} is a generic package, so in order
  485. to use it, you have to instantiate it, like this:
  486. \begin{minipage}[t]{1\columnwidth}%
  487. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  488. package My_Configuration is
  489. type Keys is (Foo, Bar);
  490. type Defaults_Array is array (Keys) of Unbounded_String;
  491. Default_Values : constant Defaults_Array :=
  492. (Foo => To_Unbounded_String ("some foo"),
  493. Bar => To_Unbounded_String ("some bar"));
  494. package Config is new Yolk.Config_File_Parser
  495. (Key_Type => Keys,
  496. Defaults_Array_Type => Defaults_Array,
  497. Defaults => Default_Value,
  498. Config_File => "config.ini");
  499. end My_Configuration;
  500. \end{lstlisting}
  501. %
  502. \end{minipage}
  503. Here we instantiate the \emph{Config} package with \emph{config.ini}
  504. as the configuration file. This means that KEY/VALUE pairs found in
  505. this file will overwrite the default values set in the \emph{Default\_Values}
  506. array. Setting a default value to \emph{Null\_Unbounded\_String} means
  507. the value is empty.
  508. Note that the \emph{config.ini} file does not have to contain all
  509. the valid keys. It is perfectly fine to only add those keys that have
  510. non-default values to the configuration file.
  511. \subsection{Re-loading configuration files}
  512. With the \emph{Load\_File} procedure you can re-load a new configuration
  513. file into your \emph{Config} package:
  514. \begin{minipage}[t]{1\columnwidth}%
  515. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  516. My_Configuration.Config.Load_File ("new_config.ini");
  517. \end{lstlisting}
  518. %
  519. \end{minipage}
  520. Now the KEY/VALUE pairs of \emph{new\_config.ini} will overwrite the
  521. ones originally found in the \emph{config.ini} file the package was
  522. instantiated with. You can do this as many times as you like. Note
  523. that you cannot change what KEY's are valid, so if the \emph{new\_config.ini}
  524. file contains unknown keys, \emph{Load\_File} will raise the \emph{Unknown\_Key}
  525. exception.
  526. \subsection{Getting values}
  527. With instantiation and loading of configuration files out of the way,
  528. it is now time to get to the configuration values. To get the value
  529. of the \emph{Foo} key, you do:
  530. \begin{minipage}[t]{1\columnwidth}%
  531. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  532. My_Configuration.Config.Get (Foo);
  533. \end{lstlisting}
  534. %
  535. \end{minipage}
  536. There are Get functions for the following types:
  537. \begin{itemize}
  538. \item \emph{Boolean}
  539. \item \emph{Duration}
  540. \item \emph{Float}
  541. \item \emph{Integer}
  542. \item \emph{String}
  543. \item \emph{Unbounded\_String}
  544. \end{itemize}
  545. Empty keys simply return an empty \emph{String} or a \emph{Null\_Unbounded\_String},
  546. depending on the target type. If a key is empty and the target type
  547. is not a \emph{String} or an \emph{Unbounded\_String}, then the \emph{Conversion\_Error}
  548. exception is raised.
  549. \subsection{Checking if a KEY has a VALUE}
  550. You can check if a key has a value with the \emph{Has\_Value} function:
  551. \begin{minipage}[t]{1\columnwidth}%
  552. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  553. if Has_Value (Foo) then
  554. Put_Line ("Foo has a value");
  555. end if;
  556. \end{lstlisting}
  557. %
  558. \end{minipage}
  559. Basically all this function does is return \emph{Boolean} \emph{True}
  560. if the value of the given key is not a \emph{Null\_Unbounded\_String}.
  561. \section{Yolk.Configuration}
  562. This package is a bit of an oddball, as all it does is instantiate
  563. the \emph{Yolk.Config\_File\_Parser} generic with the default AWS
  564. and Yolk configuration values. This is used by Yolk internally, but
  565. also by the AWS component of your application. The instantiation looks
  566. like this:
  567. \begin{minipage}[t]{1\columnwidth}%
  568. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  569. package Config is new Config_File_Parser
  570. (Key_Type => Keys,
  571. Defaults_Array_Type => Defaults_Array,
  572. Defaults => Default_Values,
  573. Config_File => Config_File);
  574. \end{lstlisting}
  575. %
  576. \end{minipage}
  577. The \emph{Config\_File} function call return either the default Yolk
  578. configuration file (\emph{configuration/config.ini}) or a user specified
  579. configuration file given by the \emph{--yolk-config-file} command
  580. line argument, so\emph{ }starting for example the Yolk demo like this:
  581. \begin{lyxcode}
  582. ./yolk\_demo~-{}-yolk-config-file~/etc/yolk-config.ini
  583. \end{lyxcode}
  584. will force the demo to look for the \emph{/etc/yolk-config.ini} configuration
  585. file.
  586. There's a fully commented \emph{config.ini.dist} file available in
  587. the \emph{extras/} directory. I recommend taking a look at the Yolk
  588. demo application to see how the \emph{Yolk.Configuration} package
  589. is used.
  590. \subsection{Get the AWS specific configuration settings}
  591. On some occassions it might be necessary to get the AWS configuration
  592. object. This can easily be accomplished by calling the \emph{Get\_AWS\_Configuration}
  593. function:
  594. \begin{minipage}[t]{1\columnwidth}%
  595. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  596. AWS_Config : constant AWS.Config.Object :=
  597. Yolk.Configuration.Get_AWS_Configuration;
  598. \end{lstlisting}
  599. %
  600. \end{minipage}
  601. \section{Yolk.Email}
  602. Using \emph{Yolk.Email} and the child package \emph{Yolk.Email.Composer}
  603. you can build and send more or less any kind of email:
  604. \begin{itemize}
  605. \item Plain text
  606. \item Multipart/Alternative
  607. \item Multipart/Mixed
  608. \end{itemize}
  609. The package supports adding multiple SMTP servers, meaning you can
  610. add as many as you need, and the email will then be send via the first
  611. one that accepts it.
  612. The \emph{Yolk.Email} package define 4 exceptions and 3 types. The
  613. facilities for actually constructing and sending the email are found
  614. in \emph{Yolk.Email.Composer}.
  615. \subsection{Exceptions}
  616. These are:
  617. \begin{itemize}
  618. \item \emph{Attachment\_File\_Not\_Found}. Is raised if a file attachment
  619. is not found at the given path.
  620. \item \emph{No\_Address\_Set}. Is raised if the address component of a To,
  621. Reply-To, From, Bcc/Cc header is missing.
  622. \item \emph{No\_Sender\_Set\_With\_Multiple\_From}. Is raised when an email
  623. contains multiple From headers but no Sender header, as per RFC-5322,
  624. 3.6.2. http://tools.ietf.org/html/rfc5322
  625. \item \emph{No\_SMTP\_Host\_Set}. Is raised if the SMTP host list is empty,
  626. ie. no SMTP host has been set for sending the email.
  627. \end{itemize}
  628. \subsection{The Yolk.Email types}
  629. When using \emph{Yolk.Email.Composer} to build and send emails, three
  630. types declared in \emph{Yolk.Email} are central:
  631. \begin{enumerate}
  632. \item \emph{Character\_Set}
  633. \item \emph{Recipient\_Kind}
  634. \item \emph{Structure}
  635. \end{enumerate}
  636. The \emph{Character\_Set} type define what character set is used when
  637. data is added to an email \emph{Structure} object. For example looking
  638. at the \emph{Yolk.Email.Composer.Add\_From} procedure, we see that
  639. the \emph{Charset} parameter defaults to \emph{US\_ASCII}:
  640. \begin{minipage}[t]{1\columnwidth}%
  641. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  642. procedure Add_From
  643. (ES : in out Structure;
  644. Address : in String;
  645. Name : in String := "";
  646. Charset : in Character_Set := US_ASCII);
  647. \end{lstlisting}
  648. %
  649. \end{minipage}
  650. This does not mean that \emph{Yolk.Email.Composer.Add\_From} will
  651. encode \emph{Name} as \emph{US\_ASCII}, instead it means that the
  652. data given in \emph{Name} already is \emph{US\_ASCII}. So if \emph{Name}
  653. had contained an ISO-8859-1 encoded \emph{String}, then the call would've
  654. looked like this:
  655. \begin{minipage}[t]{1\columnwidth}%
  656. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  657. declare
  658. use Yolk.Email;
  659. Email : Structure;
  660. begin
  661. Composer.Add_From
  662. (ES => Email,
  663. Address => "alice@domain.tld",
  664. Name => "Alice",
  665. Charset => ISO_8859_1);
  666. end;
  667. \end{lstlisting}
  668. %
  669. \end{minipage}
  670. In this case you will end up with a From header looking like this:
  671. \begin{lyxcode}
  672. From:~=?ISO-8859-1?Q?Alice?=~<alice@domain.tld>
  673. \end{lyxcode}
  674. So bear in mind that it is your responsibility to ensure that your
  675. data, and the \emph{Character\_Set} parameter match.
  676. The \emph{Recipient\_Kind} type define the kind of recipient that
  677. is being added to an email. If you've worked with email, these three
  678. should be familiar to you:
  679. \begin{enumerate}
  680. \item \emph{Bcc}
  681. \item \emph{Cc}
  682. \item \emph{To}
  683. \end{enumerate}
  684. When adding recipients to an email \emph{Structure} the default is
  685. \emph{To}, but since not all recipients are equal, you can change
  686. the kind of recipient to \emph{Bcc} or \emph{Cc}, according to your
  687. needs.
  688. The \emph{Structure} type is at the core of it all. You declare an
  689. object to be of the \emph{Structure} type, and then you use the \emph{Yolk.Email.Composer}
  690. facilities to build and send the email.
  691. \section{Yolk.Email.Composer}
  692. The actual tools for building and sending an email is found in this
  693. package. Here are tools for building emails from the ground up and
  694. there are a few convenience procedures if you just need to send a
  695. simple email with no bells or whistles.
  696. I'm not going to go through ever procedure in this package, instead
  697. I'll show an example on how to build an email from the ground up and
  698. how to use one of the convenience procedures.
  699. \subsection{Building and sending an email, the easy way}
  700. There are two convenience procedures in \emph{Yolk.Email.Composer}
  701. for sending emails without having to do a whole lot of work/thinking.
  702. They are both named \emph{Send} and they look like this:
  703. \begin{minipage}[t]{1\columnwidth}%
  704. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  705. procedure Send
  706. (ES : in out Structure;
  707. From_Address : in String;
  708. From_Name : in String := "";
  709. To_Address : in String;
  710. To_Name : in String := "";
  711. Subject : in String;
  712. Text_Part : in String;
  713. SMTP_Server : in String := "localhost";
  714. SMTP_Port : in Positive := 25;
  715. Charset : in Character_Set := US_ASCII);
  716. procedure Send
  717. (ES : in out Structure;
  718. From_Address : in String;
  719. From_Name : in String := "";
  720. To_Address : in String;
  721. To_Name : in String := "";
  722. Subject : in String;
  723. Text_Part : in String;
  724. HTML_Part : in String;
  725. SMTP_Server : in String := "localhost";
  726. SMTP_Port : in Positive := 25;
  727. Charset : in Character_Set := US_ASCII);
  728. \end{lstlisting}
  729. %
  730. \end{minipage}
  731. As you can see, the only difference between these two is that the
  732. first one sends plain text emails, while the second one sends \emph{multipart/alternative}
  733. with both plain text and HTML parts. Usage is as simple as:
  734. \begin{minipage}[t]{1\columnwidth}%
  735. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  736. declare
  737. use Yolk.Email;
  738. Email : Structure;
  739. begin
  740. Composer.Send (ES => Email,
  741. From_Address => "alice@domain.tld",
  742. From_Name => "Alice",
  743. To_Address => "bob@domain.tld",
  744. To_Name => "Bob",
  745. Subject => "Is this thing on?",
  746. Text_Part => "Hey you!",
  747. Charset => ISO_8859_1);
  748. if Composer.Is_Send (Email) then
  749. -- Success!
  750. else
  751. -- Failure!
  752. end if;
  753. end;
  754. \end{lstlisting}
  755. %
  756. \end{minipage}
  757. It is possible, and allowed, to call some of the various other procedures
  758. prior to calling one of the convenience procedures. If for example
  759. you want to add a custom header, it can be done like this:
  760. \begin{minipage}[t]{1\columnwidth}%
  761. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  762. declare
  763. use Yolk.Email;
  764. Email : Structure;
  765. begin
  766. Composer.Add_Custom_Header (ES => Email,
  767. Name => "User-Agent",
  768. Value => "My User Agent");
  769. Composer.Send (ES => Email,
  770. From_Address => "alice@domain.tld",
  771. From_Name => "Alice",
  772. To_Address => "bob@domain.tld",
  773. To_Name => "Bob",
  774. Subject => "Is this thing on?",
  775. Text_Part => "Hey you!",
  776. Charset => ISO_8859_1);
  777. if Composer.Is_Send (Email) then
  778. -- Success!
  779. else
  780. -- Failure!
  781. end if;
  782. end;
  783. \end{lstlisting}
  784. %
  785. \end{minipage}
  786. And with that, the header \emph{User-Agent:} is now added to the email:
  787. \begin{lyxcode}
  788. User-Agent:~My~User~Agent
  789. \end{lyxcode}
  790. It hardly gets any easier than that. Lets move on and see how the
  791. above is accomplished the hard way.
  792. \subsection{Building and sending email, the hard way}
  793. It is possible to build an email from the ground up, which obviously
  794. allows for a more fine grained control over what is added. It is also
  795. a bit more complicated, but not much. Lets try and mimick the easy
  796. examples, the {}``hard'' way:
  797. \begin{minipage}[t]{1\columnwidth}%
  798. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  799. declare
  800. use Yolk.Email;
  801. Email : Structure;
  802. begin
  803. Composer.Add_Custom_Header (ES => Email,
  804. Name => "User-Agent",
  805. Value => "My User Agent");
  806. Composer.Add_From (ES => Email,
  807. Address => "alice@domain.tld",
  808. Name => "Alice",
  809. Charset => ISO_8859_1);
  810. Composer.Add_Recipient (ES => Email,
  811. Address => "bob@domain.tld",
  812. Name => "Bob");
  813. Composer.Set_Subject (ES => Email,
  814. Subject => "Is this thing on?");
  815. Composer.Set_Text_Part (ES => Email,
  816. Part => "Hey you!");
  817. Composer.Add_SMTP_Server (ES => Email,
  818. Host => "localhost");
  819. Composer.Send (ES => Email);
  820. if Composer.Is_Send (Email) then
  821. -- Success!
  822. else
  823. -- Failure!
  824. end if;
  825. end;
  826. \end{lstlisting}
  827. %
  828. \end{minipage}
  829. Harder yes, but really not all that much more difficult.
  830. \section{Yolk.Handlers}
  831. Most web applications will need to handle static content, such as
  832. PNG, HTML and CSS files. \emph{Yolk.Handlers} helps you accomplish
  833. that, so you don't have to build your own handlers for these kinds
  834. of files.
  835. The following filetypes are supported by \emph{Yolk.Handlers}:
  836. \begin{itemize}
  837. \item CSS
  838. \item GIF
  839. \item HTML
  840. \item ICO
  841. \item JPG
  842. \item JS
  843. \item PNG
  844. \item SVG
  845. \item XML
  846. \item XSL
  847. \end{itemize}
  848. The filetypes that are textual, are compressed according to the \emph{Yolk.Configuration}
  849. parameter \emph{Compress\_Static\_Content} which defaults to \emph{False}.
  850. The regular expressions for identifying these filetypes are also defined
  851. in \emph{Yolk.Configuration} by the \emph{Handler\_{*}} parameters.
  852. These regular expressions are registered by the \emph{AWS.Services.Dispatchers.URI.Register\_Regexp}
  853. procedure.
  854. There's only one procedure in the \emph{Yolk.Handlers} package:
  855. \begin{minipage}[t]{1\columnwidth}%
  856. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  857. procedure Set (RH : out AWS.Services.Dispatchers.URI.Handler);
  858. \end{lstlisting}
  859. %
  860. \end{minipage}
  861. You can see an example on how this is used in the demo file \emph{my\_handlers.adb}.
  862. There's really very little reason not to use this package for handling
  863. of static content, but it is of course not mandatory.
  864. This package makes use of the \emph{Yolk.Static\_Content} package
  865. for the actual delivery of the content to the user.
  866. \section{Yolk.Log}
  867. This package serves two purposes:
  868. \begin{enumerate}
  869. \item It contains the two callback procedures used to write AWS logging
  870. data (access and error) to syslogd.
  871. \item It creates the SQL, SQL\_Cache, SQL\_Error, SQL\_Select, Alert, Critical,
  872. Debug, Emergency, Error, Info, Notice and Warning trace handles, and
  873. activates them according to the values defined in the configuration
  874. file.
  875. \end{enumerate}
  876. Out of the box, a Yolk application requires a running syslogd daemon,
  877. as all log data is sent to syslogd. If for some reason you don't want
  878. to use syslogd, you're going to have to hack the \emph{Yolk.Log} package,
  879. or remove it entirely.
  880. The two procedures named \emph{AWS\_{*}} are used by the AWS HTTP(S)
  881. server. These should not be used for anything else - or rather: If
  882. you use them for anything else, the \emph{Message} given is going
  883. to be written to syslogd with either the AWS access log label or AWS
  884. error log label. There's absolutely no harm in this, except it might
  885. be a bit confusing when reading the log data.
  886. The \emph{Trace} procedure is the one that you will be using in your
  887. application. You can send log data to the trace handles defined in
  888. \emph{Yolk.Log.Trace\_Handles}. All log data is then sent to the syslogd
  889. daemon using the facilities set in the configuration file for the
  890. given trace handle.
  891. Using \emph{Trace} is about as easy as it gets:
  892. \begin{minipage}[t]{1\columnwidth}%
  893. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  894. Yolk.Log.Trace (Handle => Error,
  895. Message => "Secret sauce to Error!");
  896. \end{lstlisting}
  897. %
  898. \end{minipage}
  899. If you haven't activated a trace handle, then calling \emph{Trace}
  900. for that handle does nothing, ie. you don't have to remove all your
  901. \emph{Trace} calls from the code if you don't use them.
  902. Note that on many systems the Emergency messages are written to console,
  903. so be cautious about using this specific level, unless you've made
  904. certain that you can get to the messages.
  905. \section{Yolk.Not\_Found}
  906. The job of this package is to return a HTTP 404 status code and an
  907. accompanying simple \emph{not found} HTML page. It's sole function
  908. \emph{Generate} is about as simple as they come:
  909. \begin{minipage}[t]{1\columnwidth}%
  910. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  911. function Generate
  912. (Request : in AWS.Status.Data)
  913. return AWS.Response.Data;
  914. \end{lstlisting}
  915. %
  916. \end{minipage}
  917. It relies on the template file \emph{demo/exe/templates/system/404.tmpl}
  918. to generate the generic 404 HTML page, so if you want to use \emph{Yolk.Not\_Found}
  919. in your own application, then remember to bring along this file. Where
  920. the \emph{404.tmpl} is placed is defined in the configuration parameter
  921. \emph{System\_Templates\_Path}.
  922. Also worth noting is that the \emph{Yolk.Not\_Found.Generate} function
  923. is used as the default callback in the demo application. This means
  924. that all requested resources that doesn't match a registered dispatcher,
  925. is served by \emph{Yolk.Not\_Found.Generate} ie. a 404 is returned.
  926. See the \emph{demo/src/my\_handlers.adb} file for more information.
  927. \section{Yolk.Process\_Control}
  928. With \emph{Yolk.Process\_Control} you get the ability to control your
  929. application using the SIGINT, SIGPWR and SIGTERM signals. If you give
  930. your Yolk application the \emph{--pid-file} commandline argument when
  931. starting it, \emph{Yolk.Process\_Control} will create a PID file on
  932. the given location, if it is allowed to do so. This PID file will
  933. also be deleted when the application terminates. Note that the \emph{extras/rc.yolk}
  934. script handles all this transparently.
  935. \subsection{Exceptions}
  936. These are:
  937. \begin{itemize}
  938. \item \emph{Cannot\_Create\_PID\_File}. Is raised if the \emph{PID\_File}
  939. cannot be created, eg. if the application lacks permissions to write
  940. to the directory where the \emph{PID\_File} is located.
  941. \item \emph{Cannot\_Delete\_PID\_File}. Is raised if the \emph{PID\_file}
  942. cannot be deleted, eg. if the application lacks permissions to write
  943. to the directory where the \emph{PID\_File} is located, or to the
  944. \emph{PID\_File} itself.
  945. \item \emph{PID\_File\_Exists}. Is raised when the \emph{PID\_File} already
  946. exists, ie. the application is already running or it was shutdown
  947. incorrectly.
  948. \end{itemize}
  949. \subsection{Using Yolk.Process\_Control}
  950. When you use the \emph{Yolk.Process\_Control} package the \emph{Unreserve\_All\_Interrupts}
  951. pragma is used. This means that depending on the compiler used one
  952. or more interrupt signals may be affected. In the case of the GNAT
  953. compiler, this is specifically mentioned in the source of the \emph{Ada.Interrupts.Names}
  954. package:
  955. \begin{quote}
  956. -- The pragma Unreserve\_All\_Interrupts affects the following signal(s):
  957. -- SIGINT: made available for Ada handler
  958. \end{quote}
  959. Since neither SIGPWR or SIGTERM are reserved by the compiler, the
  960. \emph{Yolk.Process\_Control} package is able to assume control of
  961. 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}.
  962. If you compile Yolk with a different compiler than GNAT, then please
  963. check if one of the affected signals are reserved.
  964. There are two procedures in the \emph{Yolk.Process\_Control} package:
  965. \begin{minipage}[t]{1\columnwidth}%
  966. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  967. procedure Stop;
  968. procedure Wait;
  969. \end{lstlisting}
  970. %
  971. \end{minipage}
  972. When you call the \emph{Wait} procedure, you basically hang there
  973. until
  974. \begin{enumerate}
  975. \item The \emph{Stop} procedure is called
  976. \item The application receives a SIGINT, SIGPWR or SIGTERM signal
  977. \end{enumerate}
  978. This is quite handy for applications, that need some sort of loop
  979. to keep them from terminating. You can see an example on how this
  980. can be done in the \emph{demo/src/yolk\_demo.adb} file.
  981. When \emph{Wait} is called, subsequent calls to \emph{Wait} are ignored,
  982. unless a call to \emph{Stop} has been made or the application has
  983. received one of the SIGINT, SIGPWR or SIGTERM signals. So it's perfectly
  984. valid to do:
  985. \begin{minipage}[t]{1\columnwidth}%
  986. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  987. Wait;
  988. -- Stop called from somewhere in the app
  989. -- Do something...
  990. Wait;
  991. -- The app receives a SIGINT signal
  992. -- Do something...
  993. Wait;
  994. \end{lstlisting}
  995. %
  996. \end{minipage}
  997. Whether or not this is actually useful I don't know, but it is possible.
  998. \section{Yolk.Process\_Owner}
  999. When it is necessary to change the owner of a process, the \emph{Yolk.Process\_Owner}
  1000. package is the solution. Obviously this can also be done when starting
  1001. the application, using various shell tricks, but I find it it much
  1002. cleaner to just let the application handle it by itself.
  1003. \subsection{Exceptions}
  1004. There's only one:
  1005. \begin{enumerate}
  1006. \item \emph{Username\_Does\_Not\_Exist}. This is raised if the given username
  1007. doesn't exist on the system.
  1008. \end{enumerate}
  1009. \subsection{Using Yolk.Process\_Owner}
  1010. There's only a single procedure in this package and its specification
  1011. looks like this:
  1012. \begin{minipage}[t]{1\columnwidth}%
  1013. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1014. procedure Set_User
  1015. (Username : in String);
  1016. -- Set the process owner to Username.
  1017. \end{lstlisting}
  1018. %
  1019. \end{minipage}
  1020. Please note that when changing the user ID of the application with
  1021. \emph{Set\_User}, the group ID is changed to the first group the given
  1022. user is a member of.
  1023. Usage is as simple as expected:
  1024. \begin{minipage}[t]{1\columnwidth}%
  1025. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1026. declare
  1027. begin
  1028. Set_User (Username => "billybob");
  1029. exception
  1030. when Username_Does_Not_Exist =>
  1031. -- User is missing. Do something!
  1032. end;
  1033. \end{lstlisting}
  1034. %
  1035. \end{minipage}
  1036. In the file \emph{demo/src/yolk\_demo.adb} you'll find that \emph{Yolk.Process\_Owner.Set\_User}
  1037. is used in conjunction with the \emph{Yolk.Configuration.Yolk\_User}
  1038. parameter.
  1039. \section{Yolk.Server}
  1040. This is a convenience package to handle creating, starting and stopping
  1041. an AWS HTTP server. The biggest drawback to this package is that it
  1042. can only create and manage \emph{one} AWS server.
  1043. Note a potential manual operation when using the \emph{Yolk.Server
  1044. }package : Setting the \emph{Cache-Control} header. This can become
  1045. necessary if you
  1046. \begin{enumerate}
  1047. \item use \emph{Yolk.Server} to create and start your AWS server AND
  1048. \item use the \emph{Yolk.Handlers} package to register dispatchers for static
  1049. content AND
  1050. \item have the \emph{Compress\_Static\_Content} configuration parameter
  1051. set to \emph{True }AND
  1052. \item aren't content with the default \emph{Cache-Control} header
  1053. \end{enumerate}
  1054. In that case you can use the \emph{Yolk.Static\_Content.Set\_Cache\_Options}
  1055. procedure to work your own magic on the \emph{Cache-Control} header
  1056. sent to clients requesting static content. See the Yolk.Static\_Content
  1057. chapter for more information.
  1058. \subsection{Yolk.Server.Create}
  1059. Creating a server is done by calling the \emph{Create} function. This
  1060. function accepts one parameter that should be fairly self-explanatory.
  1061. \begin{minipage}[t]{1\columnwidth}%
  1062. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1063. type HTTP is tagged limited private;
  1064. function Create
  1065. (Unexpected : in AWS.Exceptions.Unexpected_Exception_Handler)
  1066. return HTTP;
  1067. \end{lstlisting}
  1068. %
  1069. \end{minipage}
  1070. \subsection{Yolk.Server.Start}
  1071. \begin{minipage}[t]{1\columnwidth}%
  1072. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1073. procedure Start
  1074. (WS : in out HTTP;
  1075. Dispatchers : in AWS.Dispatchers.Handler'Class);
  1076. \end{lstlisting}
  1077. %
  1078. \end{minipage}
  1079. This does as expected: Starts the server with\emph{ Dispatchers.}
  1080. When calling \emph{Start} several things happen:
  1081. \begin{enumerate}
  1082. \item If the configuration parameter \emph{Load\_MIME\_Types\_File} is \emph{True}
  1083. then the MIME types file given in \emph{MIME\_Types\_File} is loaded
  1084. into AWS.
  1085. \item If the configuration parameter \emph{Start\_WebSocket\_Servers} is
  1086. \emph{True} then the AWS WebSocket servers are started.
  1087. \item \emph{Yolk.Static\_Content.Static\_Content\_Cache\_Setup} is called
  1088. with its default parameters if the configuration parameter \emph{Compress\_Static\_Content}
  1089. is \emph{True}.
  1090. \item If session support is turned on for the server and the \emph{Session\_Data\_File}
  1091. exists, then the session data is loaded from this file.
  1092. \item The \emph{Yolk.Log.AWS\_Access\_Log\_Writer} procedure is registered
  1093. to handle all AWS access log data if the configuration parameter \emph{AWS\_Access\_Log\_Activate}
  1094. is \emph{True} .
  1095. \item The \emph{Yolk.Log.AWS\_Error\_Log\_Writer} procedure is registered
  1096. to handle all AWS error log data if the configuration parameter \emph{AWS\_Error\_Log\_Activate}
  1097. is \emph{True} .
  1098. \end{enumerate}
  1099. \subsection{Yolk.Server.Stop}
  1100. \begin{minipage}[t]{1\columnwidth}%
  1101. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1102. procedure Stop
  1103. (WS : in out HTTP);
  1104. \end{lstlisting}
  1105. %
  1106. \end{minipage}
  1107. This does as expected: Stops everything that was started when the
  1108. \emph{Yolk.Server.Start} call was made. Note that if sessions support
  1109. is turned on for the server, then the \emph{Dispatchers} are switched
  1110. for a plain \emph{Not Found} dispatcher when \emph{Stop} is called.
  1111. This is done to prevent session tampering while the server is shutting
  1112. down.
  1113. \section{Yolk.Static\_Content}
  1114. Most web applications have a lot of static content, ie. stuff that
  1115. rarely changes. Things like PNG's, HTML, CSS and Javascript. These
  1116. are content types that are common for most websites, so a application
  1117. is going to have to handle these in some way. This is where \emph{Yolk.Static\_Content}
  1118. comes in. Two kinds of files are handled by \emph{Yolk.Static\_Content}:
  1119. \begin{itemize}
  1120. \item Compressable (XML, HTML, CSS, JS and so on)
  1121. \item Non-compressable (PNG, JPG, GIF, ICO and so on)
  1122. \end{itemize}
  1123. It is up to you, the user, to decide whether a specific kind of file
  1124. is compressable or not - the package does not make any such assumptions.
  1125. The difference between the two, is that compressable files are compressed
  1126. prior to delivery, if the clients HTTP request includes a \emph{Accept-Encoding:
  1127. gzip} header. Non-compressable files are simply returned as is. For
  1128. both kinds, a generic 404 is returned if the requested file doesn't
  1129. exist.
  1130. \emph{Yolk.Static\_Content} is affected by five configuration settings:
  1131. \begin{itemize}
  1132. \item Compress\_Static\_Content
  1133. \item Compress\_Static\_Content\_Minimum\_File\_Size
  1134. \item Compressed\_Static\_Content\_Cache
  1135. \item Compressed\_Static\_Content\_Max\_Age
  1136. \item WWW\_Root
  1137. \end{itemize}
  1138. You should carefully read the \emph{demo/exe/configuration/config.ini}
  1139. file for information on what exactly these do.
  1140. \subsection{Yolk.Static\_Content.Static\_Content\_Cache\_Setup}
  1141. The configuration parameter \emph{Compressed\_Static\_Content\_Cache}
  1142. defines where the compressed version of the static content is saved.
  1143. When your application is started, this directory may or may not exist,
  1144. and it may or may not contain various compressed files. To make sure
  1145. that the directory exists and is empty, you should call the \emph{Static\_Content\_Cache\_Setup}
  1146. procedure:
  1147. \begin{minipage}[t]{1\columnwidth}%
  1148. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1149. procedure Static_Content_Cache_Setup
  1150. (No_Cache : in Boolean := False;
  1151. No_Store : in Boolean := False;
  1152. No_Transform : in Boolean := False;
  1153. Max_Age : in AWS.Messages.Delta_Seconds := 86400;
  1154. S_Max_Age : in AWS.Messages.Delta_Seconds :=
  1155. AWS.Messages.Unset;
  1156. Public : in Boolean := False;
  1157. Must_Revalidate : in Boolean := True;
  1158. Proxy_Revalidate : in Boolean := False);
  1159. \end{lstlisting}
  1160. %
  1161. \end{minipage}
  1162. This procedure creates the \emph{Compressed\_Static\_Content\_Cache}
  1163. directory if it doesn't already exists and if it exists, it deletes
  1164. everything in it. So basically you're left with an empty directory
  1165. after a call to this procedure.
  1166. The parameters defines the content of the \emph{Cache-Control} header
  1167. sent to the user agent when a request for static content is made.
  1168. The default parameters are fairly sane, and will result in a cache
  1169. header looking like this:
  1170. \begin{minipage}[t]{1\columnwidth}%
  1171. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1172. Cache-Control: max-age=86400, must-revalidate
  1173. \end{lstlisting}
  1174. %
  1175. \end{minipage}
  1176. Read the \href{http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html\#sec14.9}{HTTP/1.1 Cache-Control header definition}
  1177. for more information on what the various settings do.
  1178. If you use \emph{Yolk.Server} to create and start your AWS server,
  1179. then this called is made automatically with it's default parameters.
  1180. If you don't use \emph{Yolk.Server} and you use the \emph{Yolk.Static\_Content}
  1181. package to serve static content, then you must call this procedure
  1182. before starting the AWS server. Calling it repeatedly will simply
  1183. wipe out the compressed cache directory and reset the \emph{Control\_Cache}
  1184. header according to the given parameters.
  1185. \subsection{Yolk.Static\_Content.Compressable}
  1186. If your application contains a bunch of compressable files of significant
  1187. size, you can save a lot of bandwidth by using the \emph{Compressable}
  1188. function to serve them:
  1189. \begin{minipage}[t]{1\columnwidth}%
  1190. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1191. function Compressable
  1192. (Request : in AWS.Status.Data)
  1193. return AWS.Response.Data;
  1194. \end{lstlisting}
  1195. %
  1196. \end{minipage}
  1197. A natural place to call this function would be where you define your
  1198. content handlers, as seen in this, slightly altered, excerpt from
  1199. the \emph{Yolk.Handlers} package:
  1200. \begin{minipage}[t]{1\columnwidth}%
  1201. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1202. declare
  1203. package SC renames Yolk.Static_Content;
  1204. Resource_Handlers : AWS.Services.Dispatchers.URI.Handler;
  1205. begin
  1206. AWS.Services.Dispatchers.URI.Register_Regexp
  1207. (Dispatcher => Resource_Handlers,
  1208. URI => "\.css$",
  1209. Action => Create (Callback => SC.Compressable'Access));
  1210. AWS.Services.Dispatchers.URI.Register_Regexp
  1211. (Dispatcher => Resource_Handlers,
  1212. URI => "\.html$",
  1213. Action => Create (Callback => SC.Compressable'Access));
  1214. end;
  1215. \end{lstlisting}
  1216. %
  1217. \end{minipage}
  1218. Here you can see that we've defined some content handlers for CSS
  1219. and HTML files based on a few simple regular expressions, and whenever
  1220. a resource is requested that matches one of these, the corresponding
  1221. \emph{Action} callback is called, which in this example is the \emph{Compressable}
  1222. function. The following steps are then taken:
  1223. \begin{enumerate}
  1224. \item Does the requested resource exist and is it an ordinary file?
  1225. \begin{enumerate}
  1226. \item If no, then return a 404 message
  1227. \item if yes, then proceed to 2
  1228. \end{enumerate}
  1229. \item Does the client support compressed content?
  1230. \begin{enumerate}
  1231. \item If no, then return the requested resource un-compressed
  1232. \item if yes, then proceed to 3
  1233. \end{enumerate}
  1234. \item Is there a compressed version of the resource available on disk?
  1235. \begin{enumerate}
  1236. \item if no, then make one, cache it for future use, and return it
  1237. \item If yes, then proceed to 4
  1238. \end{enumerate}
  1239. \item Is the age of the compressed file <= Compressed\_Max\_Age?
  1240. \begin{enumerate}
  1241. \item If no, then delete the current file, build a new one, cache it and
  1242. return it
  1243. \item If yes, then return it
  1244. \end{enumerate}
  1245. \end{enumerate}
  1246. And that's really all there is to it. Note that \emph{Compressable}
  1247. always looks for requested content in the \emph{WWW\_Root} directory,
  1248. so if the user requests the file \emph{/css/index.css}, then the path
  1249. is going to be:
  1250. \begin{minipage}[t]{1\columnwidth}%
  1251. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1252. WWW_Root & "/css/index.ss";
  1253. \end{lstlisting}
  1254. %
  1255. \end{minipage}
  1256. Using the default configuration value for \emph{WWW\_Root}, we'll
  1257. end up with the path:
  1258. \begin{lyxcode}
  1259. static\_content/css/index.css
  1260. \end{lyxcode}
  1261. The compressed version of \emph{index.css} is saved as:
  1262. \begin{minipage}[t]{1\columnwidth}%
  1263. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1264. Compressed_Static_Content_Cache & "/css/index.css" & ".gz";
  1265. \end{lstlisting}
  1266. %
  1267. \end{minipage}
  1268. Using the default configuration value for \emph{Compressed\_Static\_Content\_Cache},
  1269. we'll end up with the path:
  1270. \begin{lyxcode}
  1271. static\_content/compressed\_cache/css/index.css.gz
  1272. \end{lyxcode}
  1273. In these two cases the paths are relative to the executable, but you
  1274. can of course also define \emph{WWW\_Root} and \emph{Compressed\_Static\_Content\_Cache}
  1275. as absolute paths in the configuration file.
  1276. \subsection{Yolk.Static\_Content.Non\_Compressable}
  1277. A lot of static content really doesn't benefit from any further compression.
  1278. This is the case for PNG files, JPEG files and a whole lot of other
  1279. kinds of files. Static content that has already been compressed, should
  1280. be handled by the \emph{Non\_Compressable} function:
  1281. \begin{minipage}[t]{1\columnwidth}%
  1282. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1283. function Non_Compressable
  1284. (Request : in AWS.Status.Data)
  1285. return AWS.Response.Data;
  1286. \end{lstlisting}
  1287. %
  1288. \end{minipage}
  1289. A call to \emph{Non\_Compressable} is much simpler compared to a call
  1290. to it's sibling function \emph{Compressable}:
  1291. \begin{enumerate}
  1292. \item Does the requested resource exist and is it an ordinary file?
  1293. \begin{enumerate}
  1294. \item If no, then return a 404 message
  1295. \item if yes, then return the file
  1296. \end{enumerate}
  1297. \end{enumerate}
  1298. And that's it. Either the resource is there, or it isn't. If the requested
  1299. resource is \emph{/images/foo.png}, then the \emph{Non\_Compressable}
  1300. function searches for the resource in:
  1301. \begin{minipage}[t]{1\columnwidth}%
  1302. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1303. WWW_Root & "/images/foo.png";
  1304. \end{lstlisting}
  1305. %
  1306. \end{minipage}
  1307. Using the default configuration value for \emph{WWW\_Root}, we'll
  1308. end up with the path:
  1309. \begin{lyxcode}
  1310. static\_content/images/foo.png
  1311. \end{lyxcode}
  1312. Just as with \emph{Compressable} a natural place to use \emph{Non\_Compressable}
  1313. is where you define you content handlers, but it can obviously be
  1314. used wherever your application handles requests for static content.
  1315. \subsection{Yolk.Static.Set\_Cache\_Options}
  1316. You can alter the \emph{Cache-Control} header sent to clients requesting
  1317. static content with a call to \emph{Set\_Cache\_Options}\@. This
  1318. is especially handy if you use the \emph{Yolk.Server} package to create
  1319. and start your server, since the initial call to \emph{Static\_Content\_Cache\_Setup}
  1320. is hidden you're forced to live with the default values given in the
  1321. \emph{Static\_Content\_Cache\_Setup} call, resulting in a \emph{Cache-Control}
  1322. header looking like this:
  1323. \begin{minipage}[t]{1\columnwidth}%
  1324. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1325. Cache-Control: max-age=86400, must-revalidate
  1326. \end{lstlisting}
  1327. %
  1328. \end{minipage}
  1329. If this is not what you want, you can use \emph{Set\_Cache\_Options}
  1330. to change it:
  1331. \begin{minipage}[t]{1\columnwidth}%
  1332. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1333. procedure Set_Cache_Options
  1334. (No_Cache : in Boolean := False;
  1335. No_Store : in Boolean := False;
  1336. No_Transform : in Boolean := False;
  1337. Max_Age : in AWS.Messages.Delta_Seconds := 86400;
  1338. S_Max_Age : in AWS.Messages.Delta_Seconds :=
  1339. AWS.Messages.Unset;
  1340. Public : in Boolean := False;
  1341. Must_Revalidate : in Boolean := True;
  1342. Proxy_Revalidate : in Boolean := False);
  1343. \end{lstlisting}
  1344. %
  1345. \end{minipage}
  1346. This MUST be called immediately after having called \emph{Yolk.Server.Start},
  1347. since the call to \emph{Static\_Content\_Cache\_Setup} in \emph{Start}
  1348. will overwrite the cache options.
  1349. \section{Yolk.Syndication}
  1350. The Atom Syndication format (\href{http://tools.ietf.org/html/rfc4287}{RFC4287})
  1351. is an XML-based document format that describes lists of related information
  1352. known as \textquotedbl{}feeds\textquotedbl{}. Atom documents are used
  1353. by many web applications as a means of publishing information to users.
  1354. It's not a complicated format, but it does require a bit of work to
  1355. construct a proper Atom feed by hand, and since I try my best to avoid
  1356. work, I made the \emph{Yolk.Syndication} package. This package makes
  1357. it {}``easy'' to put together an Atom feed document, and have it
  1358. delivered as a string or an XML/Ada DOM object.
  1359. \emph{Yolk.Syndication} helps you construct the Atom XML - it does
  1360. not check that the resulting XML is valid Atom XML, ie. that the Atom
  1361. rules have been followed, so if the Atom specification says that
  1362. \begin{quote}
  1363. atom:feed elements MUST contain exactly one atom:id element.
  1364. \end{quote}
  1365. then it is your job to make sure that your Atom feed has exactly one
  1366. such element. So before venturing into the realm of Atom, it's probably
  1367. a good idea to read \href{http://tools.ietf.org/html/rfc4287}{RFC4287}
  1368. for a good understanding of the requirements for this document format.
  1369. A basic example of how to build an Atom feed can be found in the Yolk
  1370. demo application.
  1371. There are two packages in the \emph{Yolk.Syndication} hierarchy:
  1372. \begin{itemize}
  1373. \item \emph{Yolk.Syndication} - Here the necessary types and exceptions
  1374. are defined.
  1375. \item \emph{Yolk.Syndication.Writer} - Here the functions and procedures
  1376. for actually creating an Atom feed are defined.
  1377. \end{itemize}
  1378. When time permits, I'll add a \emph{Yolk.Syndication.Reader} package
  1379. for extraction of data from an Atom feed.
  1380. \subsection{Exceptions}
  1381. There's one exception in this package:
  1382. \begin{itemize}
  1383. \item \emph{Not\_Valid\_XML}. Is raised when some Xhtml content is not valid
  1384. XML. This exception can be raised by all procedures that takes Xhtml
  1385. as content.
  1386. \end{itemize}
  1387. \subsection{The Yolk.Syndication types}
  1388. There are 5 important types in this package:
  1389. \begin{itemize}
  1390. \item \emph{Text\_Kinds}
  1391. \item \emph{Relation\_Kinds}
  1392. \item \emph{Atom\_Entry}
  1393. \item \emph{Atom\_Entry\_Source}
  1394. \item \emph{Atom\_Feed}
  1395. \end{itemize}
  1396. A few of the procedures in \emph{Yolk.Syndication.Writer} has parameters
  1397. of the \emph{Text\_Kinds} type. This identifies the kind of data that
  1398. is being added, with possible values being
  1399. \begin{itemize}
  1400. \item \emph{Text}
  1401. \item \emph{Html}
  1402. \item \emph{Xhtml}
  1403. \end{itemize}
  1404. Hopefully it's obvious what each of these refers to. Procedures that
  1405. have parameters of the \emph{Text\_Kinds} type always add data to
  1406. the feed that can be interpreted as one of these three kinds of text.
  1407. The \emph{Relation\_Kinds} type is used in correlation with links
  1408. that are added to the feed. It identifies how the link relates to
  1409. the current feed/entry. There are 5 possible relations:
  1410. \begin{itemize}
  1411. \item \emph{Alternate}: Signifies that the link points to an alternate version
  1412. of the resource described by the containing element.
  1413. \item \emph{Related}: Signifies that the link points to a resource that
  1414. is related to, but not the same as, the resource described by the
  1415. containing element.
  1416. \item \emph{Self}: Signifies that the link points to a resource that is
  1417. equivalent to the resource described by the containing element. All
  1418. feeds should have one link with a \emph{Self} relation pointing to
  1419. itself.
  1420. \item \emph{Enclosure}: Signifies that the link points to a resource that
  1421. is related to, but not the same as, the resource described by the
  1422. containing element. It also signifies that the resource potentially
  1423. is large in size and might require special handling. If \emph{Enclosure}
  1424. is used, then usually the \emph{Length} parameter is set to hint at
  1425. the size of the resource.
  1426. \item \emph{Via}: Signifies that the resource provided by the containing
  1427. element originates in the URI given by the \emph{Href} parameter of
  1428. the link element.
  1429. \end{itemize}
  1430. Finally we have the most important types:
  1431. \begin{itemize}
  1432. \item \emph{Atom\_Entry}: An entry in a feed.
  1433. \item \emph{Atom\_Entry\_Source}: The origin of an entry.
  1434. \item \emph{Atom\_Feed}: The Atom feed.
  1435. \end{itemize}
  1436. These are core to the functionality of \emph{Yolk.Syndication}, and
  1437. every single procedure and function in the \emph{Yolk.Syndication.Writer}
  1438. package use one or the other. These three types are \emph{private},
  1439. so the only way to declare an object of either one, is by calling
  1440. the \emph{New\_Atom\_Feed}, \emph{New\_Atom\_Entry} or \emph{New\_Atom\_Entry\_Source}
  1441. functions respectively.
  1442. Note that only \emph{Atom\_Feed} is thread safe. The two entry related
  1443. types are not.
  1444. \subsection{Yolk.Syndication.New\_Atom\_Feed}
  1445. This function initialize an \emph{Atom\_Feed} type, and its specification
  1446. looks like this:
  1447. \begin{minipage}[t]{1\columnwidth}%
  1448. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1449. function New_Atom_Feed
  1450. (Base_URI : in String := None;
  1451. Language : in String := None;
  1452. Max_Age : in Duration := 5_616_000.0;
  1453. Max_Entries : in Positive := 100;
  1454. Min_Entries : in Positive := 10)
  1455. return Atom_Feed;
  1456. \end{lstlisting}
  1457. %
  1458. \end{minipage}
  1459. The \emph{Base\_URI} parameter establish a base for resolving relative
  1460. references in the feed. The \emph{Language} parameter indicates the
  1461. natural language used in the feed. \emph{Max\_Age} is a duration that
  1462. determine when an entry in the feed is old enough to be deleted. \emph{Max\_Entries}
  1463. is the amount of entries kept in the feed. If there are more than
  1464. this amount of entries in the feed, then the oldest are deleted until
  1465. the feed contains \emph{Max\_Entries} entries again. \emph{Min\_Entries}
  1466. is the minimum amount of entries that must be present in the feed,
  1467. before we bother deleting entries whose age is > \emph{Max\_Age}.
  1468. If there are less than \emph{Min\_Entries} entries in the feed, then
  1469. we keep even a 100 year old entry.
  1470. What these parameters hints at, is that some automatic maintenance
  1471. is done when using \emph{Yolk.Syndication}, and this is indeed true.
  1472. Usually you do not want a feed to grow forever, and instead of having
  1473. to manually clear away old stuff, \emph{Yolk.Syndication} handles
  1474. all this for you, according to the values given when you instantiate
  1475. an \emph{Atom\_Feed} object using \emph{New\_Atom\_Feed}.
  1476. \subsection{Yolk.Syndication.New\_Atom\_Entry}
  1477. This function initialize an \emph{Atom\_Entry} type, and its specification
  1478. looks like this:
  1479. \begin{minipage}[t]{1\columnwidth}%
  1480. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1481. function New_Atom_Entry
  1482. (Base_URI : in String := None;
  1483. Language : in String := None)
  1484. return Atom_Entry;
  1485. \end{lstlisting}
  1486. %
  1487. \end{minipage}
  1488. As you can see, it's a lot simpler than the \emph{New\_Atom\_Feed}
  1489. function. This is of course because all the automatic maintenance
  1490. related parameters have already been set by they \emph{New\_Atom\_Feed}
  1491. function. All that is left is to define the \emph{Base\_URI} and the
  1492. natural \emph{Language} used by the entry.
  1493. \subsection{Yolk.Syndication.New\_Atom\_Entry\_Source}
  1494. This function initialize an \emph{Atom\_Entry\_Source} type, and its
  1495. specification looks like this:
  1496. \begin{minipage}[t]{1\columnwidth}%
  1497. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1498. function New_Atom_Entry_Source
  1499. (Base_URI : in String := None;
  1500. Language : in String := None)
  1501. return Atom_Entry_Source;
  1502. \end{lstlisting}
  1503. %
  1504. \end{minipage}
  1505. As you can see, this is very similar to the \emph{New\_Atom\_Entry}
  1506. function, since its job is to return an \emph{Atom\_Entry\_Source}
  1507. object, which is basically just an object that describes the origins
  1508. of a feed entry.
  1509. \subsection{Yolk.Syndication.Writer}
  1510. In this package we find all the tools necessary to build the Atom
  1511. XML. There are far too many subprograms in \emph{Yolk.Syndication.Writer}
  1512. to list here, so instead I'll refer you to the source code. All the
  1513. subprograms in this package work on one of the \emph{Atom\_Feed},
  1514. \emph{Atom\_Entry} or \emph{Atom\_Entry\_Source} types, for example
  1515. if you want to set a title on your feed, you'll use the \emph{Set\_Title}
  1516. procedure:
  1517. \begin{minipage}[t]{1\columnwidth}%
  1518. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1519. procedure Set_Title
  1520. (Feed : in out Atom_Feed;
  1521. Title : in String;
  1522. Base_URI : in String := None;
  1523. Language : in String := None;
  1524. Title_Kind : in Text_Kinds := Text);
  1525. \end{lstlisting}
  1526. %
  1527. \end{minipage}
  1528. Or if the title is for an entry, then:
  1529. \begin{minipage}[t]{1\columnwidth}%
  1530. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1531. procedure Set_Title
  1532. (Entr : in out Atom_Entry;
  1533. Title : in String;
  1534. Base_URI : in String := None;
  1535. Language : in String := None;
  1536. Title_Kind : in Text_Kinds := Text);
  1537. \end{lstlisting}
  1538. %
  1539. \end{minipage}
  1540. Or we could add an author to the feed/entry/entry source:
  1541. \begin{minipage}[t]{1\columnwidth}%
  1542. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1543. procedure Add_Author
  1544. (Feed : in out Atom_Feed;
  1545. Name : in String;
  1546. Base_URI : in String := None;
  1547. Email : in String := None;
  1548. Language : in String := None;
  1549. URI : in String := None);
  1550. procedure Add_Author
  1551. (Entr : in out Atom_Entry;
  1552. Name : in String;
  1553. Base_URI : in String := None;
  1554. Email : in String := None;
  1555. Language : in String := None;
  1556. URI : in String := None);
  1557. procedure Add_Author
  1558. (Entry_Source : in out Atom_Entry_Source;
  1559. Name : in String;
  1560. Base_URI : in String := None;
  1561. Email : in String := None;
  1562. Language : in String := None;
  1563. URI : in String := None);
  1564. \end{lstlisting}
  1565. %
  1566. \end{minipage}
  1567. There's actually a hint about the kind of XML element that is being
  1568. produced by these procedures. If the name of the procedure starts
  1569. with \emph{Set\_} then it hints at an XML element of which there's
  1570. only ever one. So \emph{Set\_Title} creates a \emph{<title>Foo</title>}
  1571. element, and if called again, overwrites the previous value, whereas
  1572. if the name of procedure starts with \emph{Add\_} then the Atom specification
  1573. allows for multiples of these, as can be seen with the \emph{Add\_Author}
  1574. procedure. Calling this one creates an \emph{<author>} element, and
  1575. calling it again simply adds one more author to the feed/entry/entry
  1576. source.
  1577. Most of the subprograms in this package deals directly with building
  1578. the Atom XML, but there are a few exceptions, as you will see next.
  1579. \subsection{Counting the amount of entries in a feed}
  1580. If you need to know how many entries that are currently in a feed,
  1581. the you can use the \emph{Yolk.Syndication.Writer.Amount\_Of\_Entries}
  1582. function:
  1583. \begin{minipage}[t]{1\columnwidth}%
  1584. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1585. function Amount_Of_Entries
  1586. (Feed : in Atom_Feed)
  1587. return Natural;
  1588. \end{lstlisting}
  1589. %
  1590. \end{minipage}
  1591. \subsection{Clearing and deleting entries}
  1592. There are two procedures available for clearing and deleting entries,
  1593. one for clearing all entries away, and one for deleting entries based
  1594. on their Id. Lets start with the one that clears out everything:
  1595. \begin{minipage}[t]{1\columnwidth}%
  1596. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1597. procedure Clear_Entry_List
  1598. (Feed : in out Atom_Feed);
  1599. \end{lstlisting}
  1600. %
  1601. \end{minipage}
  1602. Calling \emph{Clear\_Entry\_List} deletes every single entry that
  1603. has been added to the \emph{Feed} object so far. A less destructive
  1604. procedure is \emph{Delete\_Entry}:
  1605. \begin{minipage}[t]{1\columnwidth}%
  1606. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1607. procedure Delete_Entry
  1608. (Feed : in out Atom_Feed;
  1609. Id : in String);
  1610. \end{lstlisting}
  1611. %
  1612. \end{minipage}
  1613. Using this one, you can delete all entries whose Id is \emph{Id}.
  1614. Note that the match must be exact, so case matters. FOO is not the
  1615. same as foo.
  1616. \subsection{Getting the Atom feed}
  1617. When you've added titles, authors, categories, entries and content
  1618. to your feed, the next step is turning it into XML. This can be done
  1619. in one of two ways:
  1620. \begin{enumerate}
  1621. \item As string XML.
  1622. \item As an XML/Ada DOM XML object.
  1623. \end{enumerate}
  1624. The string XML is obviously for the final audience, whereas the DOM
  1625. XML is useful if you need to do some further work on the feed before
  1626. releasing it on the world. Here they are:
  1627. \begin{minipage}[t]{1\columnwidth}%
  1628. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1629. function Get_XML_DOM
  1630. (Feed : in Atom_Feed)
  1631. return DOM.Core.Document;
  1632. function Get_XML_String
  1633. (Feed : in Atom_Feed;
  1634. Pretty_Print : in Boolean := False)
  1635. return String;
  1636. \end{lstlisting}
  1637. %
  1638. \end{minipage}
  1639. Note that if \emph{Pretty\_Print} is \emph{True} then whitespace is
  1640. going get mangled according to these rules:
  1641. \begin{quote}
  1642. If Pretty\_Print is true, then the XML nodes will be indented so that
  1643. children nodes are to the right of their parents. It is set to False
  1644. by default because its use changes the document (addition or removal
  1645. of whitespaces among other things), which in general has no effect
  1646. for automatic tools reading the document. All whitespaces are modified
  1647. outside of elements containing nothing but text nodes. For text nodes,
  1648. leading and trailing whitespaces are also deleted.
  1649. \end{quote}
  1650. \emph{Get\_XML\_String} relies on the \emph{Write} function from XML/Ada
  1651. to generate its output, and the above quote is taken straight from
  1652. the XML/Ada source comments. It's also worth noting that \emph{Get\_XML\_String}
  1653. and \emph{Get\_XML\_DOM} both are pretty resource-hungry, so it's
  1654. probably best to cache the results for later use, instead of calling
  1655. them on each and every hit.
  1656. \section{Yolk.Utilities}
  1657. This package contains various support functionality.
  1658. \section{Yolk.Whoops}
  1659. This package contains one single procedure: \emph{Unexpected\_Exception\_Handler}.
  1660. I suspect the name gives away exactly what this procedure does. It
  1661. looks like this:
  1662. \begin{minipage}[t]{1\columnwidth}%
  1663. \begin{lstlisting}[basicstyle={\small\sffamily},frame=tblr,language=Ada,showstringspaces=false,tabsize=3,xleftmargin=1em,xrightmargin=1em]
  1664. procedure Unexpected_Exception_Handler
  1665. (E : Ada.Exceptions.Exception_Occurrence;
  1666. Log : in out AWS.Log.Object;
  1667. Error : AWS.Exceptions.Data;
  1668. Answer : in out AWS.Response.Data);
  1669. \end{lstlisting}
  1670. %
  1671. \end{minipage}
  1672. You can use this procedure to catch any and all exceptions you've
  1673. failed to catch in your application, ie. the ones AWS pickup and fail
  1674. to do anything sensible with. When \emph{Unexpected\_Reception\_Handler}
  1675. catch an exception, two things happen:
  1676. \begin{enumerate}
  1677. \item The exception is logged to the \emph{Yolk.Log}.\emph{Error }trace.
  1678. \item A HTTP status code 500 is returned to the user.
  1679. \end{enumerate}
  1680. The template used to create the HTTP code 500 error message is\emph{
  1681. demo/exe/templates/system/500.tmpl}. You can of course change this
  1682. to match the look and feel of your application. The path to the \emph{500.tmpl}
  1683. file is set by the configuration setting \emph{System\_Templates\_Path}.
  1684. You can see an example on how to use this procedure in the file \emph{demo/src/yolk\_demo.adb}.
  1685. \end{document}