PocoCapsule: Making Hello World Easier

    imageThe article talks about the experience of acquaintance with the Ioc-container PocoCapsule (C ++), the difficulties encountered and ways to overcome them. Among other things, the article includes a small example for a quick start with PocoCapsule (a simplified project “Hello World” from the official site ).



    In my humble opinion, IoC technology is an essential component of any project that is more or less important, so the proper use of an IoC container is critical. Therefore, after meeting with PocoCapsule, I decided to write this article. Not only in order to share my experience, but also in order to make sure that I did everything right and understood everything correctly, since, as you know, the best way to understand something is to try to explain it to another person.

    It took me about 6 hours to launch the “Hello world” application using the PocoCapsule. Moreover, I periodically wanted to send everything to hell, because hands drop when you see the message "failure: null", although you do everything according to the textbook. Despite the fact that a similar start in Spring IoC takes about 30-60 minutes.

    PocoCapsule is an IoC container that works with standard C ++ objects (POCO) and it makes it quite tricky. PocoCapsule cannot read the xml configuration file and directly create the required POCO objects, because in C ++ there is no reflection mechanism.

    For example, there is a class Foo:

    class Foo {
      public:
        Foo() {};
        ~Foo() {};
    }

    * This source code was highlighted with Source Code Highlighter.


    and xml container configuration:


           destroy-method="delete"
         lazy-init="false">
     



    * This source code was highlighted with Source Code Highlighter.


    After reading the xml configuration, the PocoCapsule should create an object of class Foo. But how to do that? After all, the PocoCapsule does not depend on your source code and cannot know what kind of class this Foo is and how to handle it, therefore, naturally, it cannot directly create an object of this class.

    To solve this problem, the PocoCapsule generates proxy methods for each of your classes - methods that deal directly with your classes (create, delete, etc.). So, to invoke the Foo constructor, a method will be generated:

    // ---------------------------------------
    // Proxies of constructors and factories
    // ---------------------------------------
    //
    // new Foo()
    //
    static void* _poco_proxy_0(void* _poco_this, void* _poco_params[])
    {
      Foo* _poco_var_retv;

      _poco_var_retv = new Foo();

      return (void*)_poco_var_retv;
    }

    * This source code was highlighted with Source Code Highlighter.


    To delete, respectively:

    // -------------------------------------
    //  Proxies of dup and destroy methods
    // -------------------------------------
    //
    // delete(Foo*)
    //
    static void* _poco_proxy_1(void* _poco_this, void* _poco_params[])
    {
      int _poco_i = 0;
      Foo* _poco_var_0 = (Foo*)(_poco_params[_poco_i++]);

      delete(
            _poco_var_0);

      return (void*)0UL;
    }

    * This source code was highlighted with Source Code Highlighter.


    Then, methods for registering these “poco_proxy” in the container are also generated. In the end, these proxy methods are combined in a common source file that connects to the project and is the link between your classes and the PocoCapsule.

    Problems with the original "Hello word". (Ubuntu 10.04 LTS

    environment ) I will describe in order the problems that I encountered when I met PocoCapsule and which took me so much time.
    1. After unpacking the binaries, the proxy generator does not start (bin / pxgenproxy). We have the following:
      caiiiycuk @ caiiiycuk-laptop: ~ / pococapsule-cpp / bin $ ./pxgenproxy 
      ./pxgenproxy: undefined symbol: JNI_CreateJavaVM
      

      At the same time, I have both JRE and JDK installed (pocoapsule uses Java to generate proxies and not only).

      To solve this problem, you need to set the environment variable POCOCAPSULE_DIR = (folder with the unpacked PocoCapsule). It is very old that this requirement is not described anywhere in the documentation. It is supposed that it should work out of the box, but it didn’t work for me.

      The correct algorithm is:

      caiiiycuk@caiiiycuk-laptop:~/pococapsule-cpp/bin$ export POCOCAPSULE_DIR=/home/caiiiycuk/pococapsule-cpp/
      caiiiycuk@caiiiycuk-laptop:~/pococapsule-cpp/bin$ ./pxgenproxy
      ------------------------------------------------------------
       Pocomatic Software, Dynamic Proxy Generator, version 1.0
      ------------------------------------------------------------

      Usage:

      ./pxgenproxy (xml-file|option)*

      options:
      -help : print this page
      -s=[name] : suffix and extend name of proxy file,
                   default value is '_reflx.cc'
      -H=[std-header-file] : use the specified standard header file
      -h=[usr-header-file] : use the specified user defined header file
      -r=[gather|scatte] : recursively step into imported resources and gather or scatte
                proxy generation result into one or multiple individual proxy file(s)

      caiiiycuk@caiiiycuk-laptop:~/pococapsule-cpp/bin$

      * This source code was highlighted with Source Code Highlighter.


    2. When trying to raise the context, nothing happens - we get a cheerful null instead of the context. Having done everything according to the tutorial and running the compiled main.C, we get “failure: null”, since cxtx == null:

      /****************************************************************************/
      /*  */
      /* Copyright 2006, by Pocomatic Software, LLC. All Rights Reserved.    */
      /*  */
      /****************************************************************************/
      #include "pocoapp.h"
      #include
      #include

      int main(int argc, char** argv)
      {
      POCO_AppEnv* env = POCO_AppContext::initDefaultAppEnv(argc, argv);

      POCO_AppContext* ctxt = POCO_AppContext::create("setup.xml", "file");

      if( ctxt == NULL || !ctxt->initSingletons() ) {
      printf("failure: %s\n", env->get_message());
      return -1;
      }

      ctxt->terminate();
      ctxt->destroy();

      return 0;
      }

      * This source code was highlighted with Source Code Highlighter.


      And the reason is the same “POCOCAPSULE_DIR”: if you declare this environment variable before starting, everything starts working. This is due to the fact that PocoCapsule uses JAXP by default to parse xml files. Sad but true :( As you know, carrying java for parsing xml files is not very nice ... Fortunately, there are two ways to get rid of it: use native xml-reader based on Xerces-C ++ or use encoded xml descriptors. Unfortunately, I went the first way and it only added problems. I recommend everyone to go the second way.
    3. PocoCapsule native xml-reader (libpocoxml.so) was compiled for Xerces-C ++ version 2.7, which has already gone out of fashion and will fail to get it anywhere. To solve this problem, download the pococapsule source code, install xerces-c (dev) into the system, go to the pococapsule-cpp-1.1-src / src / xmlreader folder and run make. After successful compilation, we take the suitable libpocoxml.so from the lib dad.
    4. The PocoCapsule ignores our desire to use Xerces-C ++ (libpocoxml.so) and still requires JAXP (libpocoxsl.so). The tutorial tells us that if we connect libpocoxml.so to our project, then PocoCapsule will automatically use it instead of libpocoxsl.so. Yes it is - it worked on my “Hello word” project. But in another (more complex) project, in which other libraries are also connected, connecting libpocoxml.so has no effect - the project stubbornly requires libpocoxsl.so. After unsuccessful dances with a tambourine, I stupidly changed libpocoxml.so into libpocoxsl.so and it worked.


    Among other things, the "Hello World" project on a textbook involves dynamic linking. I believe that it can be made much easier for dating needs.

    The simplest “Hello World”

    For development, I use Ubuntu 10.04 LTS and Netbeans 6.8 , as well as PocoCapsule 1.0 binaries.
    1. Create a new C ++ project. We include the header files (Project properties-> Build-> C ++ Сompiler-> Include directories: pococapsule_dir / include). We tell the linker where to look for libpococapsule.so (Project properties-> Build-> Linker-> Libraries: pococapsule_dir / lib / libpococapsule.so).
    2. Create a class Foo (Foo.h):

      #ifndef _FOO_H
      #define _FOO_H

      #include

      class Foo {
      public:
        Foo() {
          std::cout << "Hello world!" << std::endl;
        }
      };

      #endif /* _FOO_H */

      * This source code was highlighted with Source Code Highlighter.


    3. Create an xml context (context.xml):


      SYSTEM "http://www.pocomatic.com/poco-application-context.dtd">

        destroy-method="delete"
           lazy-init="false">
       



      * This source code was highlighted with Source Code Highlighter.


    4. We will generate proxy methods for our Foo class. Open the console in the project directory and execute:

      export POCOCAPSULE_DIR=(директория PocoCapsule)
      $POCOCAPSULE_DIR/bin/pxgenproxy -h=Foo.h context.xml

      * This source code was highlighted with Source Code Highlighter.


      After successful generation, the context_reflx.cc file will appear, add this file to the project so that NetBeans builds it (Sources Files-> Add Exsisting Item). Check that everything builds successfully.
    5. Encode the xml context to get rid of JAXP. Open the console in the project directory and execute:

      export POCOCAPSULE_DIR=(директория PocoCapsule)
      $POCOCAPSULE_DIR/bin/pxencode context.xml

      * This source code was highlighted with Source Code Highlighter.


      The output will get context_poco.ctx.
    6. Edit main.cpp:

      #include "pocoapp.h"
      #include
      #include

      int main(int argc, char** argv)
      {
      POCO_AppEnv* env = POCO_AppContext::initDefaultAppEnv(argc, argv);

      POCO_AppContext* ctxt = POCO_AppContext::create("context_poco.ctx", "file");

      if( ctxt == NULL || !ctxt->initSingletons() ) {
      printf("failure: %s\n", env->get_message());
      return -1;
      }

      ctxt->terminate();
      ctxt->destroy();

      return 0;
      }

      * This source code was highlighted with Source Code Highlighter.


      Running it will see "Hello World!"
      That's all :)


    Thanks for attention.

    Also popular now: