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 }