1 /*******************************************************************************
2 
3     Utility class to do more common tasks an application have to do to start
4     running.
5 
6     Copyright:
7         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
8         All rights reserved.
9 
10     License:
11         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
12         Alternatively, this file may be distributed under the terms of the Tango
13         3-Clause BSD License (see LICENSE_BSD.txt for details).
14 
15 *******************************************************************************/
16 
17 module ocean.util.app.Application;
18 
19 
20 
21 
22 import ocean.meta.types.Qualifiers;
23 
24 import ocean.util.app.model.ExtensibleClassMixin;
25 import ocean.util.app.model.IApplicationExtension;
26 import ocean.util.app.model.IApplication;
27 import ocean.util.app.ExitException;
28 
29 import ocean.io.Stdout;
30 
31 
32 
33 /*******************************************************************************
34 
35     Extensible class to do all the common task needed for an application to run.
36 
37     This class also implements its own extension interface, so it's easy to
38     write an application using the hooks in extensions without having to write
39     a separate extension. The order of this extension is 0, establishing
40     a reference order for all the other extensions. Extensions that should be
41     executed before the application hooks should have a negative order, while
42     extensions that have to be executed after the application hooks should have
43     a positive order value.
44 
45     The common usage is to derive from Application and override the run()
46     method. Optionally you can override the extensions methods too.
47 
48     Example:
49 
50     ---
51 
52     import ocean.util.app.Application;
53     import ocean.io.Stdout;
54 
55     class MyApp : Application
56     {
57         this ( )
58         {
59             super("myapp", "A test application");
60         }
61         protected override void preRun ( Application app, istring[] args )
62         {
63             if ( args.length < 4 )
64             {
65                 this.exit(1, "Too few arguments");
66             }
67         }
68         protected override int run ( istring[] args )
69         {
70             Stdout.formatln("Application is running!");
71 
72             return 0;
73         }
74         protected override void postRun ( Application app, istring[] args,
75                 int status )
76         {
77             Stdout.formatln("Application returned {}", status);
78 
79         }
80     }
81 
82     int main(istring[] args)
83     {
84         auto app = new MyApp;
85         return app.main(args);
86     }
87 
88     ---
89 
90     As seen in the example, this class also provides a clean way to exit an
91     application from anywhere in the program, the exit() method.
92 
93     The main() method is the real only needed public API, and the one calling
94     all the extension code. The real application call must be in the run()
95     method, which is abstract, and mandatory to implement.
96 
97     The full power and usefulness of this class comes from extensions though.
98 
99 *******************************************************************************/
100 
101 class Application : IApplication
102 {
103 
104     /***************************************************************************
105 
106         Adds a list of extensions (this.extensions) and methods to handle them.
107         See ExtensibleClassMixin documentation for details.
108 
109     ***************************************************************************/
110 
111     mixin ExtensibleClassMixin!(IApplicationExtension);
112 
113 
114     /***************************************************************************
115 
116         Alias of Application, for use by sub-classes without needing to import
117         ocean.util.app.Application.
118 
119     ***************************************************************************/
120 
121     protected alias .Application Application;
122 
123 
124     /***************************************************************************
125 
126         Name of the application.
127 
128         Set in the constructor and remains read-only for the rest of the life of
129         the program.
130 
131     ***************************************************************************/
132 
133     private istring name_;
134 
135 
136     /***************************************************************************
137 
138         Short description of the application.
139 
140         Usually should be set in the constructor and remain read-only for the
141         rest of the life of the program.
142 
143     ***************************************************************************/
144 
145     public istring desc;
146 
147 
148     /***************************************************************************
149 
150         Command line arguments passed to the application.
151 
152         This is only set after the main() method is called. It's available for
153         all the extensions methods though. It is usually passed as argument to
154         extension methods, so it should not be necessary to use it directly (use
155         the method extensions arguments whenever you can).
156 
157     ***************************************************************************/
158 
159     public istring[] args;
160 
161 
162     /***************************************************************************
163 
164         Application exit status code.
165 
166         This is only set after the main() method finishes. It is usually passed
167         as argument to extension methods as soon as it has a meaningful value,
168         so it should not be necessary to use it directly (use the method
169         extensions arguments whenever you can).
170 
171     ***************************************************************************/
172 
173     public int status;
174 
175 
176     /***************************************************************************
177 
178         Constructor.
179 
180         This constructor only setup the internal state of the class, but does
181         not call any extension or user code. The application runs only when the
182         main() method is called.
183 
184         Params:
185             name = name of the application
186             desc = short description of the application
187 
188     ***************************************************************************/
189 
190     public this ( istring name, istring desc )
191     {
192         this.name_ = name;
193         this.desc = desc;
194         this.status = -1;
195         this.registerExtension(this);
196     }
197 
198 
199     /***************************************************************************
200 
201         Returns:
202             the name of the application
203 
204     ***************************************************************************/
205 
206     public istring name ( )
207     {
208         return this.name_;
209     }
210 
211 
212     /***************************************************************************
213 
214         Exit cleanly from the application.
215 
216         Calling exit() will properly unwind the stack and all the destructors
217         will be called. Should be used only from the main application thread
218         though.
219 
220         Params:
221             status = status code to return to the OS
222             msg = optional message to show just before exiting
223 
224     ***************************************************************************/
225 
226     public void exit(int status, istring msg = null)
227     {
228         throw new ExitException(status, msg);
229     }
230 
231 
232     /***************************************************************************
233 
234         Runs the application.
235 
236         This method is the main public interface of the class. It triggers all
237         the extension methods and eventually calls the run() method, which is
238         the one having the actual user code.
239 
240         Params:
241             args = Command line arguments received by the application
242 
243         Returns:
244             status code to return to the OS
245 
246     ***************************************************************************/
247 
248     public int main(istring[] args)
249     {
250         ExitException exit_except = null;
251         this.args = args;
252 
253         try
254         {
255             foreach (ext; this.extensions)
256             {
257                 ext.preRun(this, args);
258             }
259 
260             this.status = this.run(args);
261 
262             foreach (ext; this.extensions)
263             {
264                 ext.postRun(this, args, this.status);
265             }
266         }
267         catch (ExitException e)
268         {
269             foreach (ext; this.extensions)
270             {
271                 e = ext.onExitException(this, args, e);
272             }
273 
274             exit_except = e;
275             this.status = e.status;
276             this.printExitException(e);
277         }
278 
279         foreach (ext; this.extensions)
280         {
281             ext.atExit(this, args, this.status, exit_except);
282         }
283 
284         return this.status;
285     }
286 
287 
288     /***************************************************************************
289 
290         Prints the message in an ExitException.
291 
292         The message is only printed if there is one, and is printed in red if
293         the exit status is not 0 (and we are in a tty).
294 
295         Params:
296             e = ExitException to print
297 
298     ***************************************************************************/
299 
300     protected void printExitException ( ExitException e )
301     {
302         if (e.message() == "")
303         {
304             return;
305         }
306         if (e.status == 0)
307         {
308             Stdout.formatln("{}", e.message());
309         }
310         else
311         {
312             Stderr.red.format("{}", e.message()).default_colour.newline;
313         }
314     }
315 
316 
317     /***************************************************************************
318 
319         Do the actual application work.
320 
321         This method is meant to be implemented by subclasses to do the actual
322         application work.
323 
324         Params:
325             args = Command line arguments as a raw list of strings
326 
327         Returns:
328             status code to return to the OS
329 
330     ***************************************************************************/
331 
332     protected abstract int run ( istring[] args );
333 
334 
335     /***************************************************************************
336 
337         Default application extension order.
338 
339     ***************************************************************************/
340 
341     public override int order ( )
342     {
343         return 0;
344     }
345 
346 
347     /***************************************************************************
348 
349         IApplicationExtension methods dummy implementation.
350 
351         This methods are implemented with "empty" implementation to ease
352         deriving from this class.
353 
354         See IApplicationExtension documentation for more information on how to
355         override this methods.
356 
357     ***************************************************************************/
358 
359     public void preRun ( IApplication app, istring[] args )
360     {
361         // Dummy implementation of the interface
362     }
363 
364     public void postRun ( IApplication app, istring[] args, int status )
365     {
366         // Dummy implementation of the interface
367     }
368 
369     public void atExit ( IApplication app, istring[] args, int status,
370             ExitException exception )
371     {
372         // Dummy implementation of the interface
373     }
374 
375     public ExitException onExitException ( IApplication app,
376             istring[] args, ExitException exception )
377     {
378         // Dummy implementation of the interface
379         return exception;
380     }
381 
382 }