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 <h1>eVaf Tutorial
</h1>
18 <h2>03 - Generator Module
</h2>
20 <p>In this section we write the Generator module. According to the specification, the Generator module has to
21 generate strong passwords in such a way that by feeding the module with the same input data we always get the
24 <h3>iGenerator interface
</h3>
26 <p>We start by defining the interface for the module and create the file
<tt>igenerator.h
</tt> in the
27 <tt>src/apps/PswGen/Generator
</tt> directory:
</p>
29 <pre class=
"hl"><span class=
"hl com">/**
</span>
30 <span class=
"hl com"> *
@file src/apps/PswGen/Generator/igenerator.h
</span>
31 <span class=
"hl com"> */
</span>
32 <span class=
"hl ppc">#ifndef __PSWGEN_GENERATOR_IGENERATOR_H
</span>
33 <span class=
"hl ppc"># define __PSWGEN_GENERATOR_IGENERATOR_H
</span>
35 <span class=
"hl ppc">#endif
</span> <span class=
"hl slc">// igenerator.h
</span><span class=
"hl ppc"></span></pre>
37 <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
40 <pre class=
"hl"><span class=
"hl ppc">#include
<QObject
></span>
41 <span class=
"hl ppc">#include
<QString
></span></pre>
43 <p>To avoid potential name collisions with other existing or future modules, we use the
<tt>eVaf::PswGen
</tt>
44 namespace for this application:
</p>
46 <pre class=
"hl"><span class=
"hl kwa">namespace
</span> eVaf
<span class=
"hl opt">{
</span>
47 <span class=
"hl kwa">namespace
</span> PswGen
<span class=
"hl opt">{
</span>
49 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen
</span>
50 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf
</span></pre>
52 <p>We call the interface class
<tt>iGenerator
</tt>. For pure abstract classes I personally prefer using the
<tt>struct
</tt> keyword, but
53 <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 <pre class=
"hl"><span class=
"hl kwc">struct
</span> iGenerator
56 <span class=
"hl opt">{
</span>
58 <span class=
"hl opt">};
</span></pre>
60 <p>We add functionality to the interface and according to the specification we need two functions -- one that
61 generates passwords and another that returns the maximum length of the password:
</p>
63 <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>
65 <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 <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>
69 <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
70 outside of any namespaces and we add it to the end of the file:
</p>
72 <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>
74 <p>This is pretty much all we need to add to the
<tt>iGenerator
</tt> interface and here is the final file:
</p>
76 <pre class=
"hl"><span class=
"hl com">/**
</span>
77 <span class=
"hl com"> *
@file src/apps/PswGen/Generator/igenerator.h
</span>
78 <span class=
"hl com"> */
</span>
80 <span class=
"hl ppc">#ifndef __PSWGEN_GENERATOR_IGENERATOR_H
</span>
81 <span class=
"hl ppc"># define __PSWGEN_GENERATOR_IGENERATOR_H
</span>
83 <span class=
"hl ppc">#include
<QObject
></span>
84 <span class=
"hl ppc">#include
<QString
></span>
86 <span class=
"hl kwa">namespace
</span> eVaf
<span class=
"hl opt">{
</span>
87 <span class=
"hl kwa">namespace
</span> PswGen
<span class=
"hl opt">{
</span>
89 <span class=
"hl com">/// Password generator interface.
</span>
90 <span class=
"hl kwb">struct
</span> iGenerator
91 <span class=
"hl opt">{
</span>
92 <span class=
"hl com">/// Generates a strong password
</span>
93 <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>
95 <span class=
"hl com">/// Returns the maximum length of generated passwords
</span>
96 <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 <span class=
"hl opt">};
</span>
100 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen
</span>
101 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf
</span>
103 <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>
105 <span class=
"hl ppc">#endif
</span> <span class=
"hl slc">// igenerator.h
</span><span class=
"hl ppc"></span></pre>
107 <p>As a final touch, we create a file called
<tt>iGenerator
</tt> with the following content:
</p>
108 <pre class=
"hl"><span class=
"hl ppc">#include
</span> <span class=
"hl pps">"igenerator.h
"</span><span class=
"hl ppc"></span></pre>
110 <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 <h3>Generator module
</h3>
114 <p>Now we write the Generator module itself. The module class has to be derived from the
<tt>Plugins::iPlugin
</tt> interface class
115 with or without the
<tt>Plugins::iPluginFactory
</tt> factory class.
</p>
117 <p>The
<tt>Plugins::iPluginFactory
</tt> factory class should be used when more than one plugins are implemented by the same
118 module. The factory class takes care of creating individual plugins whenever they are instantiated. This module implements only
119 one plugin and we opt to the implementation without the factory class.
</p>
121 <p>Create the
<tt>module.h
</tt> header file in the
<tt>src/apps/PswGen/Generator
</tt> directory:
</p>
123 <pre class=
"hl"><span class=
"hl com">/**
</span>
124 <span class=
"hl com"> *
@file src/apps/PswGen/Generator/module.h
</span>
125 <span class=
"hl com"> */
</span>
126 <span class=
"hl ppc">#ifndef __PSWGEN_GENERATOR_MODULE_H
</span>
127 <span class=
"hl ppc"># define __PSWGEN_GENERATOR_MODULE_H
</span>
129 <span class=
"hl ppc">#endif
</span> <span class=
"hl slc">// module.h
</span><span class=
"hl ppc"></span></pre>
131 <p>As this is a simple module, we define all our class in this single header file. This includes the implementation
132 of the
<tt>iGenerator
</tt> interface and also the plugin itself. Se we need to include header files for the
133 <tt>iGenerator
</tt> and
<tt>iPlugin
</tt> interfaces:
</p>
135 <pre class=
"hl"><span class=
"hl ppc">#include
</span> <span class=
"hl pps">"igenerator.h
"</span><span class=
"hl ppc"></span>
136 <span class=
"hl ppc">#include
<Plugins/iPlugin
></span></pre>
138 <p>We are going to put every public class in this module into the
<tt>eVaf::PswGen::Generator
</tt> namespace and private
139 classes into the
<tt>eVaf::PswGen::Generator::Private
</tt> namespace:
</p>
141 <pre class=
"hl"><span class=
"hl kwa">namespace
</span> eVaf
<span class=
"hl opt">{
</span>
142 <span class=
"hl kwa">namespace
</span> PswGen
<span class=
"hl opt">{
</span>
144 <span class=
"hl slc">/// Module that generates strong passwords using cryptographic methods
</span>
145 <span class=
"hl kwa">namespace
</span> Generator
<span class=
"hl opt">{
</span>
147 <span class=
"hl slc">/// Internal implementation of the Generator module
</span>
148 <span class=
"hl kwa">namespace
</span> Internal
<span class=
"hl opt">{
</span>
150 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Generator::Internal
</span>
151 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Generator
</span>
152 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen
</span>
153 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf
</span></pre>
155 <p>We call the class that implements the module simply
<tt>Module
</tt>. This is a public class and goes into the
156 <tt>eVaf::PswGen::Generator
</tt> namespace
</tt>.
</p>
158 <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
159 <span class=
"hl opt">{
</span>
162 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
164 <span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
166 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
170 <p>The
<tt>iPlugin
</tt> interface has three pure virtual methods that we need to implement in our class --
<tt>init()
</tt>,
171 <tt>done()
</tt> and
<tt>isReady()
</tt>. Since this simple module is always ready, we can return always
<tt>true
</tt> in the
172 <tt>isReady()
</tt> function. More complex modules can use a private
<tt>mReady
</tt> variable, which they set to
<tt>true
</tt>
173 once all the initialization is done.
</tt>
175 <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>
177 <span class=
"hl kwc">virtual
</span> <span class=
"hl kwb">void
</span> <span class=
"hl kwd">done
</span><span class=
"hl opt">();
</span>
179 <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 <p>We need the
<tt>iGenerator
</tt> interface object in this module and add it to the private members section:
</tt>
183 <pre class=
"hl"><span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span> <span class=
"hl slc">// Members
</span>
185 <span class=
"hl slc">/// iGenerator interface instance
</span>
186 Internal
<span class=
"hl opt">::
</span>GeneratorImpl
<span class=
"hl opt">*
</span> mGenerator
<span class=
"hl opt">;
</span></pre>
188 <p>As the
<tt>Internal::GeneratorImpl
</tt> class is not declared yet, we need to add this forward declaration before the
189 <tt>Module
</tt> class:
</p>
191 <pre class=
"hl"><span class=
"hl kwa">namespace
</span> Internal
<span class=
"hl opt">{
</span>
192 <span class=
"hl kwc">class
</span> GeneratorImpl
<span class=
"hl opt">;
</span>
193 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Generator::Internal
</span></pre>
195 <p>Then we can move forward and implement the
<tt>iGenerator
</tt> interface, which we already happened to call
196 <tt>GeneratorImpl
</tt>. This class goes into the
<tt>eVaf::PswGen::Generator::Internal
</tt> namespace.
</p>
198 <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
199 <tt>Q_INTERFACES
</tt> macro to include Qt meta-data for the
<tt>iGenerator
</tt> interface:
</p>
201 <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
202 <span class=
"hl opt">{
</span>
203 <span class=
"hl kwd">Q_OBJECT
</span>
204 <span class=
"hl kwd">Q_INTERFACES
</span><span class=
"hl opt">(
</span>eVaf::PswGen::iGenerator
<span class=
"hl opt">)
</span>
206 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
208 <span class=
"hl kwd">GeneratorImpl
</span><span class=
"hl opt">();
</span>
210 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">GeneratorImpl
</span><span class=
"hl opt">();
</span>
212 <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>
214 <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>
215 <span class=
"hl opt">};
</span></pre>
217 <p>Here is the final
<tt>module.h
</tt> file:
</p>
219 <pre class=
"hl"><span class=
"hl com">/**
</span>
220 <span class=
"hl com"> *
@file src/apps/PswGen/Generator/module.h
</span>
221 <span class=
"hl com"> */
</span>
223 <span class=
"hl ppc">#ifndef __PSWGEN_GENERATOR_MODULE_H
</span>
224 <span class=
"hl ppc"># define __PSWGEN_GENERATOR_MODULE_H
</span>
226 <span class=
"hl ppc">#include
</span> <span class=
"hl pps">"igenerator.h
"</span><span class=
"hl ppc"></span>
228 <span class=
"hl ppc">#include
<Plugins/iPlugin
></span>
230 <span class=
"hl ppc">#include
<QObject
></span>
231 <span class=
"hl ppc">#include
<QString
></span>
233 <span class=
"hl kwa">namespace
</span> eVaf
<span class=
"hl opt">{
</span>
234 <span class=
"hl kwa">namespace
</span> PswGen
<span class=
"hl opt">{
</span>
236 <span class=
"hl slc">/// Module that generates strong passwords using cryptographic methods
</span>
237 <span class=
"hl kwa">namespace
</span> Generator
<span class=
"hl opt">{
</span>
239 <span class=
"hl slc">/// Internal implementation of the Generator module
</span>
240 <span class=
"hl kwa">namespace
</span> Internal
<span class=
"hl opt">{
</span>
241 <span class=
"hl kwc">class
</span> GeneratorImpl
<span class=
"hl opt">;
</span>
242 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Generator::Internal
</span>
244 <span class=
"hl com">/// Plugins::iPlugin interface implementation.
</span>
245 <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
246 <span class=
"hl opt">{
</span>
247 <span class=
"hl kwd">Q_OBJECT
</span>
249 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
251 <span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
253 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">Module
</span><span class=
"hl opt">();
</span>
255 <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>
257 <span class=
"hl kwc">virtual
</span> <span class=
"hl kwb">void
</span> <span class=
"hl kwd">done
</span><span class=
"hl opt">();
</span>
259 <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 <span class=
"hl kwc">private
</span><span class=
"hl opt">:
</span> <span class=
"hl slc">// Members
</span>
263 <span class=
"hl slc">/// iGenerator interface instance
</span>
264 Internal
<span class=
"hl opt">::
</span>GeneratorImpl
<span class=
"hl opt">*
</span> mGenerator
<span class=
"hl opt">;
</span>
265 <span class=
"hl opt">};
</span>
267 <span class=
"hl kwa">namespace
</span> Internal
<span class=
"hl opt">{
</span>
269 <span class=
"hl com">/// iGenerator interface implementation.
</span>
270 <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
271 <span class=
"hl opt">{
</span>
272 <span class=
"hl kwd">Q_OBJECT
</span>
273 <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 <span class=
"hl kwc">public
</span><span class=
"hl opt">:
</span>
277 <span class=
"hl kwd">GeneratorImpl
</span><span class=
"hl opt">();
</span>
279 <span class=
"hl kwc">virtual
</span> <span class=
"hl opt">~
</span><span class=
"hl kwd">GeneratorImpl
</span><span class=
"hl opt">();
</span>
281 <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>
283 <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>
284 <span class=
"hl opt">};
</span>
286 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Generator::Internal
</span>
288 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen::Generator
</span>
289 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf::PswGen
</span>
290 <span class=
"hl opt">}
</span> <span class=
"hl slc">// namespace eVaf
</span>
292 <span class=
"hl ppc">#endif
</span> <span class=
"hl slc">// module.h
</span><span class=
"hl ppc"></span></pre>
294 <p>Continue implementing the
<a href=
"pswgen04.html">Generator Module
</a>.
</p>