]> vaikene.ee Git - evaf/blob - www/pswgen03.html
Added iApp::exec() function, which enters the Qt event loop and runs the application.
[evaf] / www / pswgen03.html
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 <html lang="et" xmlns="http://www.w3.org/1999/xhtml" xml:lang="et">
3
4 <head>
5 <meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" />
6 <title>eVaf Tutorial - 03 - Generator Module</title>
7 <meta name="Author" content="Enar Väikene" />
8 <meta name="description" content="eVaf Tutorial" />
9 <meta name="keywords" content="evaf c++ application development framework tutorial password generator" />
10 <link rel="StyleSheet" href="evaf.css" type="text/css" media="all" />
11 <link rel="StyleSheet" href="highlight.css" type="text/css" media="all" />
12 </head>
13
14 <body>
15
16 <p>Next: <a href="pswgen04.html">04 - Generator Module</a>, Previous: <a href="pswgen02.html">02 - Preparations</a></p>
17 <h1>eVaf Tutorial</h1>
18
19 <h2>03 - Generator Module</h2>
20
21 <p>In this section we write the Generator module. According to the specification, the Generator module has to
22 generate strong passwords in such a way that by feeding the module with the same input data we always get the
23 same password.</p>
24
25 <h3>iGenerator interface</h3>
26
27 <p>We start by defining the interface for the module and create the file <tt>igenerator.h</tt> in the
28 <tt>src/apps/PswGen/Generator</tt> directory:</p>
29
30 <pre class="hl"><span class="hl com">/**</span>
31 <span class="hl com"> * &#64;file src/apps/PswGen/Generator/igenerator.h</span>
32 <span class="hl com"> */</span>
33 <span class="hl ppc">#ifndef __PSWGEN_GENERATOR_IGENERATOR_H</span>
34 <span class="hl ppc"># define __PSWGEN_GENERATOR_IGENERATOR_H</span>
35
36 <span class="hl ppc">#endif</span> <span class="hl slc">// igenerator.h</span><span class="hl ppc"></span></pre>
37
38 <p>We need to include some Qt header files -- <tt>QObject</tt> is almost always needed and <tt>QString</tt> we need for input data and generated
39 passwords:</p>
40
41 <pre class="hl"><span class="hl ppc">#include &lt;QObject&gt;</span>
42 <span class="hl ppc">#include &lt;QString&gt;</span></pre>
43
44 <p>To avoid potential name collisions with other existing or future modules, we use the <tt>eVaf::PswGen</tt>
45 namespace for this application:</p>
46
47 <pre class="hl"><span class="hl kwa">namespace</span> eVaf <span class="hl opt">{</span>
48 <span class="hl kwa">namespace</span> PswGen <span class="hl opt">{</span>
49
50 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen</span>
51 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf</span></pre>
52
53 <p>We call the interface class <tt>iGenerator</tt>. For pure abstract classes I personally prefer using the <tt>struct</tt> keyword, but
54 <tt>class</tt> works as well if you remember to add the <tt>public</tt> keyword to make methods in the class public.</p>
55
56 <pre class="hl"><span class="hl kwc">struct</span> iGenerator
57 <span class="hl opt">{</span>
58
59 <span class="hl opt">};</span></pre>
60
61 <p>We add functionality to the interface and according to the specification we need two functions -- one that
62 generates passwords and another that returns the maximum length of the password:</p>
63
64 <pre class="hl"><span class="hl kwc">virtual</span> QString <span class="hl kwd">generatePassword</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">,</span> QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> masterPassword<span class="hl opt">,</span> <span class="hl kwb">int</span> length<span class="hl opt">,</span> uint flags <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">)</span> <span class="hl kwb">const</span> <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">;</span>
65
66 <span class="hl kwc">virtual</span> <span class="hl kwb">int</span> <span class="hl kwd">maxLength</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">;</span></pre>
67
68 <p>I am training myself to use the style of writing declarations like <tt>"QString const &amp;"</tt>, which refers to a non-mutable <tt>QString</tt> object similar to <tt>"int maxLength() const"</tt>, which is a function that does not modify the object's data members. Feel free to use the traditional way of writing <tt>"const QString &amp;"</tt> if this looks weird to you.</p>
69
70 <p>We use the <tt>Q_DECLARE_INTERFACE</tt> macro to add Qt meta-data to the interface. eVaf interfaces are type-casted using the <tt>qobject_cast&lt;&gt;()</tt> template function and it requires meta-data to verify type and version of the interface. The <tt>Q_DECLARE_INTERFACE</tt> macro has to be
71 outside of any namespaces and we add it to the end of the file:</p>
72
73 <pre class="hl"><span class="hl kwd">Q_DECLARE_INTERFACE</span><span class="hl opt">(</span>eVaf<span class="hl opt">::</span>PswGen<span class="hl opt">::</span>iGenerator<span class="hl opt">,</span> <span class="hl str">&quot;eVaf.PswGen.iGenerator/1.0&quot;</span><span class="hl opt">)</span></pre>
74
75 <p>This is pretty much all we need to add to the <tt>iGenerator</tt> interface and here is the final file:</p>
76
77 <pre class="hl"><span class="hl com">/**</span>
78 <span class="hl com"> * &#64;file src/apps/PswGen/Generator/igenerator.h</span>
79 <span class="hl com"> */</span>
80
81 <span class="hl ppc">#ifndef __PSWGEN_GENERATOR_IGENERATOR_H</span>
82 <span class="hl ppc"># define __PSWGEN_GENERATOR_IGENERATOR_H</span>
83
84 <span class="hl ppc">#include &lt;QObject&gt;</span>
85 <span class="hl ppc">#include &lt;QString&gt;</span>
86
87 <span class="hl kwa">namespace</span> eVaf <span class="hl opt">{</span>
88 <span class="hl kwa">namespace</span> PswGen <span class="hl opt">{</span>
89
90 <span class="hl com">/// Password generator interface.</span>
91 <span class="hl kwb">struct</span> iGenerator
92 <span class="hl opt">{</span>
93 <span class="hl com">/// Generates a strong password</span>
94 <span class="hl kwc">virtual</span> QString <span class="hl kwd">generatePassword</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">,</span> QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> masterPassword<span class="hl opt">,</span> <span class="hl kwb">int</span> length<span class="hl opt">,</span> uint flags <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">)</span> <span class="hl kwb">const</span> <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">;</span>
95
96 <span class="hl com">/// Returns the maximum length of generated passwords</span>
97 <span class="hl kwc">virtual</span> <span class="hl kwb">int</span> <span class="hl kwd">maxLength</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">;</span>
98
99 <span class="hl opt">};</span>
100
101 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen</span>
102 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf</span>
103
104 <span class="hl kwd">Q_DECLARE_INTERFACE</span><span class="hl opt">(</span>eVaf<span class="hl opt">::</span>PswGen<span class="hl opt">::</span>iGenerator<span class="hl opt">,</span> <span class="hl str">&quot;eVaf.PswGen.iGenerator/1.0&quot;</span><span class="hl opt">)</span>
105
106 <span class="hl ppc">#endif</span> <span class="hl slc">// igenerator.h</span><span class="hl ppc"></span></pre>
107
108 <p>As a final touch, we create a file called <tt>iGenerator</tt> with the following content:</p>
109 <pre class="hl"><span class="hl ppc">#include</span> <span class="hl pps">&quot;igenerator.h&quot;</span><span class="hl ppc"></span></pre>
110
111 <p>With this file in place other modules can use <tt>#include "Generator/iGenerator"</tt> instead of <tt>#include "Generator/igenerator.h"</tt> similar to other eVaf and Qt include files.</p>
112
113 <h3>Generator module</h3>
114
115 <p>Now we write the Generator module itself. The module class has to be derived from the <tt>Plugins::iPlugin</tt> interface class
116 with or without the <tt>Plugins::iPluginFactory</tt> factory class.</p>
117
118 <p>The <tt>Plugins::iPluginFactory</tt> factory class should be used when more than one plugins are implemented by the same
119 module. The factory class takes care of creating individual plugins whenever they are instantiated. This module implements only
120 one plugin and we opt to the implementation without the factory class.</p>
121
122 <p>Create the <tt>module.h</tt> header file in the <tt>src/apps/PswGen/Generator</tt> directory:</p>
123
124 <pre class="hl"><span class="hl com">/**</span>
125 <span class="hl com"> * &#64;file src/apps/PswGen/Generator/module.h</span>
126 <span class="hl com"> */</span>
127 <span class="hl ppc">#ifndef __PSWGEN_GENERATOR_MODULE_H</span>
128 <span class="hl ppc"># define __PSWGEN_GENERATOR_MODULE_H</span>
129
130 <span class="hl ppc">#endif</span> <span class="hl slc">// module.h</span><span class="hl ppc"></span></pre>
131
132 <p>As this is a simple module, we define all our class in this single header file. This includes the implementation
133 of the <tt>iGenerator</tt> interface and also the plugin itself. Se we need to include header files for the
134 <tt>iGenerator</tt> and <tt>iPlugin</tt> interfaces:</p>
135
136 <pre class="hl"><span class="hl ppc">#include</span> <span class="hl pps">&quot;igenerator.h&quot;</span><span class="hl ppc"></span>
137 <span class="hl ppc">#include &lt;Plugins/iPlugin&gt;</span></pre>
138
139 <p>We are going to put every public class in this module into the <tt>eVaf::PswGen::Generator</tt> namespace and private
140 classes into the <tt>eVaf::PswGen::Generator::Private</tt> namespace:</p>
141
142 <pre class="hl"><span class="hl kwa">namespace</span> eVaf <span class="hl opt">{</span>
143 <span class="hl kwa">namespace</span> PswGen <span class="hl opt">{</span>
144
145 <span class="hl slc">/// Module that generates strong passwords using cryptographic methods</span>
146 <span class="hl kwa">namespace</span> Generator <span class="hl opt">{</span>
147
148 <span class="hl slc">/// Internal implementation of the Generator module</span>
149 <span class="hl kwa">namespace</span> Internal <span class="hl opt">{</span>
150
151 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Generator::Internal</span>
152 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Generator</span>
153 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen</span>
154 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf</span></pre>
155
156 <p>We call the class that implements the module simply <tt>Module</tt>. This is a public class and goes into the
157 <tt>eVaf::PswGen::Generator</tt> namespace</tt>.</p>
158
159 <pre class="hl"><span class="hl kwc">class</span> Module <span class="hl opt">:</span> <span class="hl kwc">public</span> Plugins<span class="hl opt">::</span>iPlugin
160 <span class="hl opt">{</span>
161 Q_OBJECT
162
163 <span class="hl kwc">public</span><span class="hl opt">:</span>
164
165 <span class="hl kwd">Module</span><span class="hl opt">();</span>
166
167 <span class="hl kwc">virtual</span> <span class="hl opt">~</span><span class="hl kwd">Module</span><span class="hl opt">();</span>
168
169 }</span></pre>
170
171 <p>The <tt>iPlugin</tt> interface has three pure virtual methods that we need to implement in our class -- <tt>init()</tt>,
172 <tt>done()</tt> and <tt>isReady()</tt>. Since this simple module is always ready, we can return always <tt>true</tt> in the
173 <tt>isReady()</tt> function. More complex modules can use a private <tt>mReady</tt> variable, which they set to <tt>true</tt>
174 once all the initialization is done.</tt>
175
176 <pre class="hl"><span class="hl kwc">virtual</span> <span class="hl kwb">bool</span> <span class="hl kwd">init</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> args<span class="hl opt">);</span>
177
178 <span class="hl kwc">virtual</span> <span class="hl kwb">void</span> <span class="hl kwd">done</span><span class="hl opt">();</span>
179
180 <span class="hl kwc">virtual</span> <span class="hl kwb">bool</span> <span class="hl kwd">isReady</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return true</span><span class="hl opt">; }</pre>
181
182 <p>We need the <tt>iGenerator</tt> interface object in this module and add it to the private members section:</tt>
183
184 <pre class="hl"><span class="hl kwc">private</span><span class="hl opt">:</span> <span class="hl slc">// Members</span>
185
186 <span class="hl slc">/// iGenerator interface instance</span>
187 Internal<span class="hl opt">::</span>GeneratorImpl <span class="hl opt">*</span> mGenerator<span class="hl opt">;</span></pre>
188
189 <p>As the <tt>Internal::GeneratorImpl</tt> class is not declared yet, we need to add this forward declaration before the
190 <tt>Module</tt> class:</p>
191
192 <pre class="hl"><span class="hl kwa">namespace</span> Internal <span class="hl opt">{</span>
193 <span class="hl kwc">class</span> GeneratorImpl<span class="hl opt">;</span>
194 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Generator::Internal</span></pre>
195
196 <p>Then we can move forward and implement the <tt>iGenerator</tt> interface, which we already happened to call
197 <tt>GeneratorImpl</tt>. This class goes into the <tt>eVaf::PswGen::Generator::Internal</tt> namespace.</p>
198
199 <p>The <tt>GeneratorImpl</tt> class needs to be derived both from <tt>QObject</tt> and from <tt>iGenerator</tt>. We also have to use the
200 <tt>Q_INTERFACES</tt> macro to include Qt meta-data for the <tt>iGenerator</tt> interface:</p>
201
202 <pre class="hl"><span class="hl kwc">class</span> GeneratorImpl <span class="hl opt">:</span> <span class="hl kwc">public</span> QObject<span class="hl opt">,</span> <span class="hl kwc">public</span> iGenerator
203 <span class="hl opt">{</span>
204 <span class="hl kwd">Q_OBJECT</span>
205 <span class="hl kwd">Q_INTERFACES</span><span class="hl opt">(</span>eVaf::PswGen::iGenerator<span class="hl opt">)</span>
206
207 <span class="hl kwc">public</span><span class="hl opt">:</span>
208
209 <span class="hl kwd">GeneratorImpl</span><span class="hl opt">();</span>
210
211 <span class="hl kwc">virtual</span> <span class="hl opt">~</span><span class="hl kwd">GeneratorImpl</span><span class="hl opt">();</span>
212
213 <span class="hl kwc">virtual</span> QString <span class="hl kwd">generatePassword</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">,</span> QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> masterPassword<span class="hl opt">,</span> <span class="hl kwb">int</span> length<span class="hl opt">,</span> uint flags <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">)</span> <span class="hl kwb">const</span><span class="hl opt">;</span>
214
215 <span class="hl kwc">virtual</span> <span class="hl kwb">int</span> <span class="hl kwd">maxLength</span><span class="hl opt">()</span> <span class="hl kwb">const;</span>
216 <span class="hl opt">};</span></pre>
217
218 <p>Here is the final <tt>module.h</tt> file:</p>
219
220 <pre class="hl"><span class="hl com">/**</span>
221 <span class="hl com"> * &#64;file src/apps/PswGen/Generator/module.h</span>
222 <span class="hl com"> */</span>
223
224 <span class="hl ppc">#ifndef __PSWGEN_GENERATOR_MODULE_H</span>
225 <span class="hl ppc"># define __PSWGEN_GENERATOR_MODULE_H</span>
226
227 <span class="hl ppc">#include</span> <span class="hl pps">&quot;igenerator.h&quot;</span><span class="hl ppc"></span>
228
229 <span class="hl ppc">#include &lt;Plugins/iPlugin&gt;</span>
230
231 <span class="hl ppc">#include &lt;QObject&gt;</span>
232 <span class="hl ppc">#include &lt;QString&gt;</span>
233
234 <span class="hl kwa">namespace</span> eVaf <span class="hl opt">{</span>
235 <span class="hl kwa">namespace</span> PswGen <span class="hl opt">{</span>
236
237 <span class="hl slc">/// Module that generates strong passwords using cryptographic methods</span>
238 <span class="hl kwa">namespace</span> Generator <span class="hl opt">{</span>
239
240 <span class="hl slc">/// Internal implementation of the Generator module</span>
241 <span class="hl kwa">namespace</span> Internal <span class="hl opt">{</span>
242 <span class="hl kwc">class</span> GeneratorImpl<span class="hl opt">;</span>
243 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Generator::Internal</span>
244
245 <span class="hl com">/// Plugins::iPlugin interface implementation.</span>
246 <span class="hl kwc">class</span> Module <span class="hl opt">:</span> <span class="hl kwc">public</span> Plugins<span class="hl opt">::</span>iPlugin
247 <span class="hl opt">{</span>
248 <span class="hl kwd">Q_OBJECT</span>
249
250 <span class="hl kwc">public</span><span class="hl opt">:</span>
251
252 <span class="hl kwd">Module</span><span class="hl opt">();</span>
253
254 <span class="hl kwc">virtual</span> <span class="hl opt">~</span><span class="hl kwd">Module</span><span class="hl opt">();</span>
255
256 <span class="hl kwc">virtual</span> <span class="hl kwb">bool</span> <span class="hl kwd">init</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> args<span class="hl opt">);</span>
257
258 <span class="hl kwc">virtual</span> <span class="hl kwb">void</span> <span class="hl kwd">done</span><span class="hl opt">();</span>
259
260 <span class="hl kwc">virtual</span> <span class="hl kwb">bool</span> <span class="hl kwd">isReady</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return true</span><span class="hl opt">; }</span>
261
262 <span class="hl kwc">private</span><span class="hl opt">:</span> <span class="hl slc">// Members</span>
263
264 <span class="hl slc">/// iGenerator interface instance</span>
265 Internal<span class="hl opt">::</span>GeneratorImpl <span class="hl opt">*</span> mGenerator<span class="hl opt">;</span>
266 <span class="hl opt">};</span>
267
268 <span class="hl kwa">namespace</span> Internal <span class="hl opt">{</span>
269
270 <span class="hl com">/// iGenerator interface implementation.</span>
271 <span class="hl kwc">class</span> GeneratorImpl <span class="hl opt">:</span> <span class="hl kwc">public</span> QObject<span class="hl opt">,</span> <span class="hl kwc">public</span> iGenerator
272 <span class="hl opt">{</span>
273 <span class="hl kwd">Q_OBJECT</span>
274 <span class="hl kwd">Q_INTERFACES</span><span class="hl opt">(</span>eVaf<span class="hl opt">::</span>PswGen<span class="hl opt">::</span>iGenerator<span class="hl opt">)</span>
275
276 <span class="hl kwc">public</span><span class="hl opt">:</span>
277
278 <span class="hl kwd">GeneratorImpl</span><span class="hl opt">();</span>
279
280 <span class="hl kwc">virtual</span> <span class="hl opt">~</span><span class="hl kwd">GeneratorImpl</span><span class="hl opt">();</span>
281
282 <span class="hl kwc">virtual</span> QString <span class="hl kwd">generatePassword</span><span class="hl opt">(</span>QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> name<span class="hl opt">,</span> QString <span class="hl kwb">const</span> <span class="hl opt">&amp;</span> masterPassword<span class="hl opt">,</span> <span class="hl kwb">int</span> length<span class="hl opt">,</span> uint flags <span class="hl opt">=</span> <span class="hl num">0</span><span class="hl opt">)</span> <span class="hl kwb">const</span><span class="hl opt">;</span>
283
284 <span class="hl kwc">virtual</span> <span class="hl kwb">int</span> <span class="hl kwd">maxLength</span><span class="hl opt">()</span> <span class="hl kwb">const</span> <span class="hl opt">{</span> <span class="hl kwa">return</span> <span class="hl num">24</span><span class="hl opt">; }</span>
285 <span class="hl opt">};</span>
286
287 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Generator::Internal</span>
288
289 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen::Generator</span>
290 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf::PswGen</span>
291 <span class="hl opt">}</span> <span class="hl slc">// namespace eVaf</span>
292
293 <span class="hl ppc">#endif</span> <span class="hl slc">// module.h</span><span class="hl ppc"></span></pre>
294
295 <p>Continue implementing the <a href="pswgen04.html">Generator Module</a>.</p>
296
297 </body>
298
299 </html>