Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Tutorial

Common Application
Server Application

This tutorial will demonstrate how to use the "Boost.Application" to build the two types of application supported in the current version, thus it is divided into 2 parts, as follows.

[Note] Note

The code presented here can be compiled on UNIX variants and Windows without modifications.

[Tip] Tip

An more complex tutorial can be found at Code Project

Like name aready explan, this is a most usual type of aplication. Exemples of this kind of application are a command application (e.g. more, tail, ls), mail client application and so on. In general matter, this kind of application does not execute to a long period of time, like a server application are.

Header

Boost.Application is a header-only library. It comes with a convenience header file which is the only one you need to include to make use of all library features:

#include <boost/application.hpp>

Functor Application Class

After that, a functor class (that will hold user application code) need be created.

1class myapp
{
public:

   myapp(application::context& context)
      : context_(context)
   {
   }

   2int operator()()
   {
      // your application logic here!
      return 0;
   }

private:
   application::context& context_;

};

1

Your application functor class

2

Application operator, this is like a 'main' function

An important things here is 'context'. Context is your application 'aspect' pool and you will use it to retrieves application information and control your application.

Refer to 'Application Context' to know more.

Standard Main Function

The standard "main" function that will instantiate our application (myapp) looks like as:

int main(int argc, char *argv[])
{
   1application::context app_context;

   2myapp app(app_context);

   3return application::launch<application::common>(app, app_context);
}

1

Your application context that hold a 'aspect' pool

2

Your application functor instance

3

Starts the application as a common application type.

This is the simplest application that we can have.

Action Loop and Wait For Termination Request

The library provides 2 methods to wait execution of application:

  • Inspect the 'status' aspect state;
  • Using 'wait_for_termination_request' aspect.

Here we will use the first version.

class myapp
{
public:

   myapp(application::context& context)
      : context_(context)
   {
   }

   int operator()()
   {
      1boost::shared_ptr<application::status> st =
         context_.find<application::status>();

      2while(st->state() != application::status::stopped)
      {
	     3boost::this_thread::sleep(boost::posix_time::seconds(1));
         // your application logic here!
      }

      return 0;
   }

   // check in next stage
   bool stop()
   {
      return true;
   }

private:
   application::context& context_;

};

1

Retrieves 'status' aspect from your context

2

Check 'aspect' status 'state'

3

Your application loop body

[Note] Note

By default the signals 'SIGINT', 'SIGTERM' and 'SIGABRT' will change internal state os aspect 'status' of application from 'application::status::running' to 'application::status::stopped'.

User can customize the default behaviour, refer to 'Customize Signals/Handlers'

Handlers

Handlers is the way that you can define a custom action to a event.

Here we will add a 'stop' handler to application.

[Note] Note

Note that the way to 'fire' an event changes depending on the chosen application and operating system types. e.g.: The user can use 'kill -INT <PID>' on UNIX, send CTRL-C on Windows console, or press the link 'stop' on SCM

class myapp
{
public:

   myapp(application::context& context)
      : context_(context)
   {
   }

   int operator()()
   {
      context_.find<application::wait_for_termination_request>()->wait();
      return 0;
   }

   1bool stop()
   {
      std::cout << "Stoping my application..." << std::endl;
	
      2return true;
   }

private:
   application::context& context_;

};

1

Define your 'stop' handler that will be called when the 'stop' event will be fired.

2

return true to stop, false to ignore

Now you need tie a 'stop' handler to 'termination_handler' aspect, we will use 'auto_handler' to do this:

int main(int argc, char *argv[])
{
   application::context app_context;

   1application::auto_handler<myapp> app(app_context);

   2return application::launch<application::common>(app, app_context);
}

1

Tie stop to termination_handler using default behaviour

2

Starts the application as a common application type.

Everything that has been seen so far, applies to the application server. But server application (mainly in windows side) provide other features. For sample on Windows Side we have pause and resume handlers and installation functionality.

Instantiate a Server

To transform the 'common' seen application in a 'server' you need only change the template application mode on main, like this:

int main(int argc, char *argv[])
{
   application::context app_context;

   1application::auto_handler<myapp> app(app_context);

   2return application::launch<application::server>(app, app_context);
}

1

Tie stop to termination_handler using default behaviour

2

Note that now we are using 'application::server' as template param

Now if you compile on Windows, a Service will be created, and on Unix Variants a background process/Daemon will be created.

[Important] Important

In oder to use a Windows service, you have to install it. Installation makes the SCM aware of the service and cause the SCM to add it to the list of services that appears in Services Console of Control Painel.

Refer to setup example on 'example/setup' folder to know how to build a setup for Windows Service.

After instalation you can see your service on SCM.

scm

On POSIX system you need only execute your application.

terminal

Optional Handlers (Windows)

Now that you know the basis, we will do a simplest server and add some new handles to it.

Let's start doing a simple server with simple log to file funcionality (If you desire you can change this code to use Boost.Log).

class myapp
{
public:

   myapp(application::context& context)
      : context_(context)
   {
   }

   int operator()()
   {
      std::string logfile
         = context_.find<application::path>()->executable_path().string() + "/log.txt";

      my_log_file_.open(logfile.c_str());
      my_log_file_ << "Start Log..." << std::endl;

      1context_.find<application::wait_for_termination_request>()->wait();

      return 0;
   }

   2bool stop()
   {
      my_log_file_ << "Stoping my application..." << std::endl;
      my_log_file_.close();

      3return true;
   }

   4bool pause()
   {
      my_log_file_ << "Pause my application..." << std::endl;

      5return true;
   }

   6bool resume()
   {
      my_log_file_ << "Resume my application..." << std::endl;

      7return true;
   }

private:
   application::context& context_;

   8std::ofstream my_log_file_;

};

1

Here we use wait_for_termination_request instead application loop

2

The 'stop' handler, available on windows and posix

3

Return true to resume, false to tell to application mode engine to ignore the event

4

The 'pause' handler, available on windows only, ignored on posix

5

Return true to resume, false to tell to application mode engine to ignore the event

6

The 'resume' handler, available on windows only, ignored on posix

7

Return true to resume, false to tell to application mode engine to ignore the event

8

Our simple log

And in cpp file:

int main(int argc, char *argv[])
{
   1application::context app_context;

   2application::auto_handler<myapp> app(app_context);

   3app_context.insert<application::path>(
      boost::make_shared<application::path_default_behaviour>(argc, argv));

   4app_context.insert<application::args>(
      boost::make_shared<application::args>(argc, argv));

   5return application::launch<application::server>(app, app_context);
}

1

Application Context

2

Tie stop, pause, resume handlers using default behaviour

3

Path manipulation aspect, to be used to get executable module path to use in log

4

Arg manipulation aspect

5

Note that now we are using 'application::server' as template param

Now, after start your service you will see "pause" on SCM.

scm_pause

Then if you start your application and pause and then resume, in log you will have some thing like this:

Start Log...
work_thread (1s)
work_thread (2s)
work_thread (3s)
Pause my application...
work_thread paused...(4s)
work_thread paused...(5s)
work_thread paused...(6s)
work_thread paused...(7s)
work_thread paused...(8s)
work_thread paused...(9s)
work_thread paused...(10s)
Resume my application...
work_thread (11s)
work_thread (12s)
work_thread (13s)
Stoping my application...
[Note] Note

By default, the log (log.txt) file is located in the same directory as the application binary.

[Note] Note

On POSIX system you will see only 'Start Log... Stoping my application...'

[Note] Note

Windows Service

If you do not add 'stop handler' to your class, you will block the autonomy of the User to stop the service, see:

scm_stop


PrevUpHomeNext