Click here to Skip to main content
15,885,278 members
Articles / Programming Languages / C++

Creating a New Application Mode for Boost.Application (0.4) Library

Rate me:
Please Sign up or sign in to vote.
4.29/5 (11 votes)
19 Dec 2013CPOL10 min read 22.8K   154   28   1
How to create a new application mode for Boost.Application (0.4) Library

Image 1

Introduction

This article presents an introduction to the new version of proposed ‘Application’ library to boost.org. This new version is based on ‘aspect’ concept and is labeled as 0.4.x version.

Warning!

Some time ago, I wrote 2 articles based on version 0.3.

Creating a Work Queue

http://www.codeproject.com/Articles/664709/Creating-a-Work-Queue-Thread-Pool-Application-Usin

Note that an updated sample of this code is present in the new version of library (0.4) in example/uuid_client_server folder.

Create a Windows Service Application Using the Boost.Application Library

http://www.codeproject.com/Articles/662221/Create-a-Windows-Service-Application-Using-the-Boo

Note that an updated sample of this code is present in the new version of library (0.4) in example/work_queue folder.

Note that version 0.3 is no longer maintained! Version 0.4 is now maintained and receives regular updates.

Feedback

If you are a Boost user, and use Boost Mailing Lists, please provide your feedback about the library, directly on list. (Specify if you think the library should be accepted as part of boost.org.)

If you are a CodeProject user, please provide your feedback about the library directly on this page.

Bugs

If you find any BUGS, please send them to me at re.tf@acm.org.

Caution

The Boost.Application is not yet an official Boost C++ library. It wasn't reviewed and can't be downloaded from www.boost.org. This beta is available to boost community to know the real interest and get comments for refinement. The intention is to submit the library for formal review, if the community thinks that it is interesting!

What is Boost.Application

Boost.Application provides an application environment, or starting point to any people that want a basic infrastructure to build a system application on Windows or Unix Variants (e.g. Linux, MacOS).

Boost.Application allows users to extend library functionality too, e.g. in this article, an Apache Httpd Module will be constructed as an “Boost Application Mode”.

An important concept of Boost.Application is the 'aspects', that was proposed by 'Vicente J. Botet Escriba'. An “aspect concept” allows easy extension and customization of library components.

Boost.Application provides many useful ready-to-use features, e.g:

  • Run application as Windows Service
  • Run application as UNIX/POSIX Daemon
  • Plugin extension system
  • Process(executable) Single instance Instantiation support
  • Application SIGNAL/Callbacks customization
  • Windows Service Setup feature
  • Application Mode extension (that will be presented in this article)
  • And many others

Boost.Application Resources

You can download the library from GitHub here.

An online documentation (under construction) is available here.

Library Official ‘Application Modes’

An ‘application mode’ is a ready to use feature that is offered by the library, in this version we have 2 official application modes (types):

  • Common Application: This kind of application is an usual Interactive Terminal/Console Application.
  • Server Application: This kind of application generates a Service (Windows), or a background process/Daemon (Unix).

This article will present how to extend library modes, it shows how to create a new simple ‘application mode’ to be used on Apache Web Server. With this ‘mode’ ready, the user can use it to generate any Apache Content Generator Module.

This is not official “library mode”, it is only a sample that illustrates how to extend library functionality. The resultant mode is very simple and doesn't expose all Apache Httpd Server API functionality. We will only implement a simple ‘Content Generator’ that supports the HTTP GET VERB!

0. Basic Setup

This library is not an official Boost.org library yet, and it uses other 2 not official libraries too, then the installation is not too easy.

1) The first step is to download the last version of boost and build it.

The build process of boost is not very easy too, but a good documentation is provided, refer to this link.

Or you can check this good article to help with build.

2) The second step is to download:

  1. Boost.Application (https://github.com/retf/Boost.Application/zipball/master)
  2. Boost.TypeIndex (https://github.com/apolukhin/type_index/zipball/master)
  3. Boost.Singularity (https://github.com/cppmaven/Singularity/zipball/master)

You can unzip each of it on your ‘c:\’ or other directory. We will configure Visual Studio Project to find these directories later!

Note that Boost.org is moving to git, thus the folder structure of libraries can change in future, refer to boost.org to know more!

1. Apache HTTP Web Server

The Apache Web Server is one of the most deployed Web Server today. This article presents how to use Boost.Application library to create a way to extend Apache Web Server.

The Apache Server comprises a relative small core, and a lot of modules. Modules commonly held on a /modules directory are loaded at runtime. This article shows how to build a new application mode for “Boost.Application”, that can be used to generate new ‘Apache Content Generator Module’.

1.1 Install Apache

You need to install Apache with include files.

You can download a Apache (2.3) for Windows here.

The screen below shows how to install Apache:

Image 2

Image 3

Image 4

Image 5

Important Note: In this article, the focus platform is Windows, but if you are a UNIX/LINUX user you can adapt this to your platform. “Boost.Application” is Multiplatform, like any Boost library.

2. Setup a Visual Studio Project

The Visual Studio 2012 will be used to build the project, and all provided samples are for this version only. All code and projects are provided; check the download link on top of page.

2.1 Create Visual Studio Project skeletons to Apache Module.

Open Visual Studio, and create a Win32 Project. On ‘Application Settings’, select ‘DLL and ‘Empty Project’’.

Image 6

Image 7

2.2 On project, open properties window and add needed include directories to “C/C++ -> General -> Additional Include Directories”

The needed directories are:

Name Directories (example)
Your Main Boost	C:\boost_1_54_0
Your Boost.Application	E:\project.boost.app.v4.4
Your Boost.TypeIndex	E:\type_index
Your Boost.Singularity	E:\singularity
Your Apache API/APR	C:\Program Files (x86)\Apache Software Foundation\Apache2.2\include

Note that your directories may have different names and locations.

Image 8

2.3 On project, open properties window again, and add boost libs directories to “Linker -> General -> Additional Library Directories”

Note that when you build boost, the common place to libs are: e.g.: C:\boost_1_54_0\stage\lib.

Image 9

2.4 We need do something to Apache “Linker -> General -> Additional Library Directories”

Image 10

2.5 On project, add a new source file called “main.cpp”, and a header called “mymode.hpp”

Image 11

Image 12

3. Boost.Application -> Application Mode

As previously discussed, by default (at this first version), Boost.Application provides two ready to use application modes: common and server application modes. In a general way, user will use one of these modes (types) to build a server or a terminal application. If provided modes don’t accomplish what the user desires, the user needs to extend the library mode.

The ‘application mode’ extension is the most advanced feature of Boost.Application, and a new mode in a general way, needs work with some 3rdpart API, e.g. on Windows, the ‘server’ mode encapsulate and abstract to final user the Windows Service API.

In our case, we will work (encapsulate on the new mode) the Apache API, we will use Apache Portable Runtime (APR) inside our mode.

In the diagram below, we have a schematic diagram of the components of “Boost.Application”, is highlighted in red which we modify/add.

Image 13

For complete reference, refer to this link.

4. Starting Our Application Mode

On ‘main.cpp’, we will have our client code, and on “mymode.hpp” we will have our mode implementation.

At this point, it is good you take a look at the roadmap to learn how a simple application is made:

http://www.dokfile.com/appbeta4/docs/libs/application/doc/html/boost_application/roadmap.html

We will create a new mode to be used in step “H”.

4.1 Application Mode Introduction

Basically, an “Application Module” is composed of one ‘mode class’, which needs to have a defined structure (constructor, and methods) and a collection of ‘aspects’.

An ‘aspect’ can be any class, but “Boost.Application” provides some base class that allows us to create a special type of ‘aspects’, e.g. a callback (handler) aspect.

To know more, refer to this link.

In our case, we will have one aspect to handle ‘apache log’, one to “web application name”, one for “content type” and the last will be our handler that will be called when a GET request arrives.

5. Our Aspects (Number 4 on Diagram)

Here, I will present the implementation of all aspects to out mode.

5.1 Log Aspect

This aspect will provide log functionality to the final user. Take a look at:

C:\Program Files (x86)\Apache Software Foundation\Apache2.2\logs 

Inside this folder, we have many logs. Our “log aspect” will provide to user a way to use this log!

httpd.exe: Could not reliably determine the server's fully qualified domain name, using 192.168.0.9 for ServerName.

[Wed Dec 11 09:38:05 2013] [notice] Apache/2.2.25 (Win32) configured -- resuming normal operations  
<span style="font-size: 9pt;">
[Wed Dec 11 09:38:05 2013] [notice] Server built: Jul 10 2013 01:52:12 </span> 
<span style="font-size: 9pt;">
[Wed Dec 11 09:38:05 2013] [notice] Parent: Created child process 6836 
</span><span style="font-size: 9pt;">
[Wed Dec 11 09:38:12 2013] [warn] Page requested! Boost.Application! </span>
Apache log sample
C++
class apache_log
{
   friend class apache2_httpd_mod;

public:
   apache_log(request_rec *r)
      : r_(r) { }

   void error(const std::string& msg)
   {
      ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r_->server, msg.c_str());
   }

   void information(const std::string& msg)
   {
      ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_INFO, 0, r_->server, msg.c_str());
   }

   void warning(const std::string& msg)
   {
      ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_WARNING, 0, r_->server, msg.c_str());
   }
private:
   request_rec *r_;

};
The apache_log Aspect.

5.2 Web Application Name Aspect

This aspect is used to identify our application on Apache, thus Apache can know if it handles our request or decline.

e.g.: http://localhost:8080/boostapp

The ‘boostapp’ is our web application name.

C++
class web_app_name
{
   friend class apache2_httpd_mod;

public:
   web_app_name(const std::string& web_app_name)
      : web_app_name_ (web_app_name)
   {}

private:
   std::string web_app_name_;
};
The web_app_name Aspect

5.3 Content Type Aspect

This aspect is used to identify our content that will be pushed to browser client.

e.g.: "text/html;charset=ascii"

C++
class content_type
{
   friend class apache2_httpd_mod;

public:
   content_type(const std::string& my_content_type)
      : content_type_ (my_content_type)
   {}

private:
   std::string content_type_;
};
The content_type Aspect

5.4 GET VERB Handler Aspect

This aspect is the most important, it will allow the final user of our mode to tie a custom ‘content generator’ handler to HTTP GET VERB.

C++
class http_get_verb_handler : public handler<std::string>
{
public:
   http_get_verb_handler(const parameter_callback& callback)
      : handler<std::string>(callback) {}

   http_get_verb_handler(const singleton_callback& callback)
      : handler<std::string>(callback) {}
};
The http_get_verb_handler Aspect

Note that we inherit from ‘boost::application::handler<:string>’.

To know more about provided handlers, refer to this link.

6. Implement our Aspects (Number 2 on Diagram)

The ‘Application Mode’ is a class that will be initiated by ‘boost::application::launch’ function. On our mode design, each request that arrives will launch a new apache2_httpd_mod! Here, the mode designer is free to do anything.

C++
class apache2_httpd_mod
{

public:

   static int mode()
   {
      static int id = new_run_mode<int>();
      return id;
   }

   template <typename Application, typename RequestRec>
   apache2_httpd_mod(Application& myapp, RequestRec &rr, 
      context &cxt, boost::system::error_code& ec)
      : error_(OK) 
   {
   }

   template <typename Application, typename RequestRec>
   apache2_httpd_mod(Application& myapp, RequestRec &rr, 
      boost::singularity<context> &cxt, boost::system::error_code& ec)
      : error_(OK) 
   {
   }

   int run() { return error_; }

protected:

    // ...

};
The apache2_httpd_mod mode skeleton

Note that all ‘modes’ need respect these signatures.

The ‘mode’ method is used to identify a mode, and we have 2 constructors, one that supports singularity, and the other that will receive a ‘context’ as parameter, and ‘run’ method that in our case returns one status code to client.

After that, the designer of the module is free to add any other method that is necessary. Let’s do this now:

C++
class apache2_httpd_mod
{

public:

   static int mode()
   {
      static int id = new_run_mode<int>();
      return id;
   }

   template <typename Application, typename RequestRec>
   apache2_httpd_mod(Application& myapp, RequestRec &rr, 
      context &cxt, boost::system::error_code& ec)
      : error_(OK) 
   {
      handle_request(myapp, rr, cxt);
   }

   template <typename Application, typename RequestRec>
   apache2_httpd_mod(Application& myapp, RequestRec &rr, 
      boost::singularity<context> &cxt, boost::system::error_code& ec)
      : error_(OK) 
   {
      handle_request(myapp, rr, cxt.get_global());
   }

   int run() { return error_; }

protected:

   template <typename Application, typename RequestRec>
   void handle_request(Application& myapp, RequestRec &rr, context &cxt)
   {
      // default impl aspects

      if(!cxt.find<run_mode>())
      {
         cxt.insert<run_mode>(
            csbl::make_shared<run_mode>(mode()));
      }

      if(!cxt.find<status>())
      {
         cxt.insert<status>(
            csbl::make_shared<status>(status::running));
      }

      csbl::shared_ptr<web_app_name> appname = cxt.find<web_app_name>();

      if(!appname)
      {
         error_ = DECLINED; return;
      }

      if (strcmp(rr.handler, appname->web_app_name_.c_str())) 
      {
         error_ = DECLINED; return;
      }

      // we allow only GET
      
      // Add other http verbs 
      // ...

      if(rr.method_number != M_GET)
      {
         error_ = HTTP_METHOD_NOT_ALLOWED; return;
      }
         
      // GET

      csbl::shared_ptr<http_get_verb_handler> http_get_verb =
         cxt.find<http_get_verb_handler>();
      
      if(http_get_verb)
      {
         // apache log 
         cxt.insert<apache_log>(csbl::make_shared<apache_log>(&rr));

         csbl::shared_ptr<content_type> contenttype = 
            cxt.find<content_type>();

         if(contenttype)
            ap_set_content_type(&rr, contenttype->content_type_.c_str());
         else
            ap_set_content_type(&rr, "text/html;charset=ascii");

         // check if we have any callback to call

         handler<std::string>::parameter_callback* parameter = 0;

         if(http_get_verb->callback(parameter))
         {
            ap_rputs((*parameter)(cxt).c_str(), &rr); return;
         }

         handler<std::string>::singleton_callback* singleton = 0;

         if(http_get_verb->callback(singleton))
         {
            ap_rputs((*singleton)().c_str(), &rr); return;
         }
      }

      // we need set application_state to stop
      cxt.find<status>()->state(status::stoped);

      // we cant find any handler, generate apache error
      error_ = HTTP_INTERNAL_SERVER_ERROR;
   }

private:

   int error_;

};
Full apache2_httpd_mod mode that uses Apache APR

6.1 Export all to Apache be aware of our mode

To do this, we will implement a MACRO that the final user will need to add on “.cpp” file.

C++
#define BOOST_APPLICATION_APACHE_REGISTER_TEST_MY_MODE(h, m)                   \
extern "C" {                                                                   \
void boost_application_register_hooks(apr_pool_t *p)                           \
{                                                                              \
   ap_hook_handler(h, NULL, NULL, APR_HOOK_MIDDLE);                            \
}                                                                              \
                                                                               \
module AP_MODULE_DECLARE_DATA m = {                                            \
    STANDARD20_MODULE_STUFF,                                                   \
    NULL,                                                                      \
    NULL,                                                                      \
    NULL,                                                                      \
    NULL,                                                                      \
    NULL,                                                                      \
    boost_application_register_hooks                                           \
}; }
Export Macro

6.2 Mode Conclusion

Now we have our mode ready to use. Now, our role is no more as ‘Mode Designer’, now our role will be ‘Mode User’ (client/final user)

7. Using the New ‘Mode’

Here, I will present how the final/client user can use our new mode.

7.1 Create an Application Functor Class

On our ‘main.cpp’, we will create our functor class.

C++
class my_apache2_httpd_content_generator_mod
{
public:

   int operator()(application::context& context) 
   {
      return 0; 
   }

   std::string get(application::context& context)
   {
      context.insert<content_type>(
         boost::make_shared<content_type>("text/html;charset=ascii"));

      std::stringstream htm;

      htm.str("");
      htm << "<html>"
          << "   <head>"
          << "      <title>Boost.Application Test</title>"
          << "   </head>"
          << ""
          << "   <body>"
          << "      <h1> Hello Boost.Application Version " 
          << application::library_version_string() << "!"
          << "      </h1>"
          << "      <br/>"
          << "      Apache HTTPd Mod."
          << "      <br/>"
          << "   </body>"
          << "</html>"
          ;

      boost::shared_ptr<apache_log> apachelog = context.find<apache_log>();
      if(apachelog)
      {
         // log something on apache log file
         apachelog->warning("Page requested!");
      }

      return htm.str();
   }
};
Application Functor Class

In ‘get’ method, we will generate our content, in this case the content will be a simple HTML page. We will use our ‘log aspect’ tool!

7.2 Implement “main” Function

This function will be called by Apache on a request, and we use it to setup our application mode at run-time.

C++
// an application will be launched to handle each request that arrives.
extern "C" int myhandle(request_rec *r)
{   
   my_apache2_httpd_content_generator_mod app;

   application::context app_context;

   app_context.insert<web_app_name>(
      boost::make_shared<web_app_name>("boostapp"));

   handler<std::string>::parameter_callback my_http_get_verb
      = boost::bind<std::string>(
         &my_apache2_httpd_content_generator_mod::get, &app, _1);

   app_context.insert<http_get_verb_handler>(
      boost::make_shared<
         http_get_verb_handler>(my_http_get_verb));

   return application::launch<apache2_httpd_mod>(app, *r, app_context);
}
Our main function (myhandler)

Apache Web Server calls this function passing a ‘request_rec’ that we will pass to our mode.

Then, we create our application functor class, our context, that will hold all of our aspects. To know more about context, refer to this link.

After that, we use the mode aspects that we just created. Note that we bind our ‘get’ method to our ‘http_get_verb_handler’ aspect.

The last step is to tie all together and run the ‘content generator’, we do this using “application::launch<apache2_httpd_mod>” function that receives our mode as template parameter.

7.3 Register our ‘main (myhandler)’ Function

The final step is to register our main function, using our MACRO.

C++
// register request function and mod on apache server
BOOST_APPLICATION_APACHE_REGISTER_TEST_MY_MODE(myhandle, my_boost_app_mod)
Register myhandler

8. Configure httpd.cong

Now is the time to configure our ‘httpd.cong’ file.

This file is located in ‘/conf’, in my case:

C:\Program Files (x86)\Apache Software Foundation\Apache2.2\conf 

8.1 Add our module on httpd.cong

Open file and add this:

C++
// file continues ...
#LoadModule version_module modules/mod_version.so
#LoadModule vhost_alias_module modules/mod_vhost_alias.so

LoadModule my_boost_app_mod "C:\Users\Renato Tegon Forti\Desktop\mymod\Debug\mymod.dll"
<Location /boostapp>
  SetHandler boostapp
</Location>
   

// file continues ...
Httpd Configuration

Change "C:\Users\Renato Tegon Forti\Desktop\mymod\Debug\mymod.dll" to your path.

9. Test

Go to your Apache folder, and start Apache as Admin.

Image 14

9.1 Open your Browser and request page, and you need see:

Image 15

10. Conclusion

Here, I show how the user can extend the Library, many other ready to use features are available, one that I like a lot is plug-in system. Take a look at the documentation.

And please send your comments and let me know if you liked this article or not. Also, please feel free to give suggestions and report bugs .

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Systems Engineer
Brazil Brazil
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 4 Pin
Grant Rostig9-Mar-19 13:24
Grant Rostig9-Mar-19 13:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.