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">
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" />
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>
19 <h2>03 - Generator Module
</h2>
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
25 <h3>iGenerator interface
</h3>
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>
30 <pre class=
"hl"><span class=
"hl com">/**
</span>
31 <span class=
"hl com"> *
@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>
36 <span class=
"hl ppc">#endif
</span> <span class=
"hl slc">// igenerator.h
</span><span class=
"hl ppc"></span></pre>
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
41 <pre class=
"hl"><span class=
"hl ppc">#include
<QObject
></span>
42 <span class=
"hl ppc">#include
<QString
></span></pre>
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>
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>
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>
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>
56 <pre class=
"hl"><span class=
"hl kwc">struct
</span> iGenerator
57 <span class=
"hl opt">{
</span>
59 <span class=
"hl opt">};
</span></pre>
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>
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">&</span> name
<span class=
"hl opt">,
</span> QString
<span class=
"hl kwb">const
</span> <span class=
"hl opt">&</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>
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>
68 <p>I am training myself to use the style of writing declarations like
<tt>"QString const &"</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 &"</tt> if this looks weird to you.
</p>
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
<>()
</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>
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">"eVaf.PswGen.iGenerator/
1.0"</span><span class=
"hl opt">)
</span></pre>
75 <p>This is pretty much all we need to add to the
<tt>iGenerator
</tt> interface and here is the final file:
</p>
77 <pre class=
"hl"><span class=
"hl com">/**
</span>
78 <span class=
"hl com"> *
@file src/apps/PswGen/Generator/igenerator.h
</span>
79 <span class=
"hl com"> */
</span>
81 <span class=
"hl ppc">#ifndef __PSWGEN_GENERATOR_IGENERATOR_H
</span>
82 <span class=
"hl ppc"># define __PSWGEN_GENERATOR_IGENERATOR_H
</span>
84 <span class=
"hl ppc">#include
<QObject
></span>
85 <span class=
"hl ppc">#include
<QString
></span>
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>
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">&</span> name
<span class=
"hl opt">,
</span> QString
<span class=
"hl kwb">const
</span> <span class=
"hl opt">&</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>
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>
99 <span class=
"hl opt">};
</span>
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>
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">"eVaf.PswGen.iGenerator/
1.0"</span><span class=
"hl opt">)
</span>
106 <span class=
"hl ppc">#endif
</span> <span class=
"hl slc">// igenerator.h
</span><span class=
"hl ppc"></span></pre>
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">"igenerator.h
"</span><span class=
"hl ppc"></span></pre>
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>
113 <h3>Generator module
</h3>
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>
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>
122 <p>Create the
<tt>module.h
</tt> header file in the
<tt>src/apps/PswGen/Generator
</tt> directory:
</p>
124 <pre class=
"hl"><span class=
"hl com">/**
</span>
125 <span class=
"hl com"> *
@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>
130 <span class=
"hl ppc">#endif
</span> <span class=
"hl slc">// module.h
</span><span class=
"hl ppc"></span></pre>
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>
136 <pre class=
"hl"><span class=
"hl ppc">#include
</span> <span class=
"hl pps">"igenerator.h
"</span><span class=
"hl ppc"></span>
137 <span class=
"hl ppc">#include
<Plugins/iPlugin
></span></pre>
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>
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>
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>
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>
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>
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>
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>
163 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
165 <span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
167 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
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>
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">&</span> args
<span class=
"hl opt">);
</span>
178 <span class=
"hl kwc">virtual
</span> <span class=
"hl kwb">void
</span> <span class=
"hl kwd">done
</span><span class=
"hl opt">();
</span>
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>
182 <p>We need the
<tt>iGenerator
</tt> interface object in this module and add it to the private members section:
</tt>
184 <pre class=
"hl"><span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span> <span class=
"hl slc">// Members
</span>
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>
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>
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>
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>
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>
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>
207 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
209 <span class=
"hl kwd">GeneratorImpl
</span><span class=
"hl opt">();
</span>
211 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">GeneratorImpl
</span><span class=
"hl opt">();
</span>
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">&</span> name
<span class=
"hl opt">,
</span> QString
<span class=
"hl kwb">const
</span> <span class=
"hl opt">&</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>
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>
218 <p>Here is the final
<tt>module.h
</tt> file:
</p>
220 <pre class=
"hl"><span class=
"hl com">/**
</span>
221 <span class=
"hl com"> *
@file src/apps/PswGen/Generator/module.h
</span>
222 <span class=
"hl com"> */
</span>
224 <span class=
"hl ppc">#ifndef __PSWGEN_GENERATOR_MODULE_H
</span>
225 <span class=
"hl ppc"># define __PSWGEN_GENERATOR_MODULE_H
</span>
227 <span class=
"hl ppc">#include
</span> <span class=
"hl pps">"igenerator.h
"</span><span class=
"hl ppc"></span>
229 <span class=
"hl ppc">#include
<Plugins/iPlugin
></span>
231 <span class=
"hl ppc">#include
<QObject
></span>
232 <span class=
"hl ppc">#include
<QString
></span>
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>
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>
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>
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>
250 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
252 <span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
254 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
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">&</span> args
<span class=
"hl opt">);
</span>
258 <span class=
"hl kwc">virtual
</span> <span class=
"hl kwb">void
</span> <span class=
"hl kwd">done
</span><span class=
"hl opt">();
</span>
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>
262 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span> <span class=
"hl slc">// Members
</span>
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>
268 <span class=
"hl kwa">namespace
</span> Internal
<span class=
"hl opt">{
</span>
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>
276 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
278 <span class=
"hl kwd">GeneratorImpl
</span><span class=
"hl opt">();
</span>
280 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">GeneratorImpl
</span><span class=
"hl opt">();
</span>
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">&</span> name
<span class=
"hl opt">,
</span> QString
<span class=
"hl kwb">const
</span> <span class=
"hl opt">&</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>
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>
287 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Generator::Internal
</span>
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>
293 <span class=
"hl ppc">#endif
</span> <span class=
"hl slc">// module.h
</span><span class=
"hl ppc"></span></pre>
295 <p>Continue implementing the
<a href=
"pswgen04.html">Generator Module
</a>.
</p>