<html>
<head>
<base href="https://wiki.asterisk.org/wiki">
<link rel="stylesheet" href="/wiki/s/en/2171/18/9/_/styles/combined.css?spaceKey=TOP&forWysiwyg=true" type="text/css">
</head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
<h2><a href="https://wiki.asterisk.org/wiki/display/TOP/Component+Base+Class">Component Base Class</a></h2>
<h4>Page <b>edited</b> by <a href="https://wiki.asterisk.org/wiki/display/~beagles">Brent Eagles</a>
</h4>
<br/>
<h4>Changes (29)</h4>
<div id="page-diffs">
<table class="diff" cellpadding="0" cellspacing="0">
<tr><td class="diff-snipped" >...<br></td></tr>
<tr><td class="diff-unchanged" >{panel:title=Component Base Class|titleBGColor=#2022FF|bgColor=#7788FF} <br>* Rationale <br></td></tr>
<tr><td class="diff-changed-lines" >** Components share <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">a</span> common start up and shutdown <span class="diff-changed-words">pattern<span class="diff-added-chars"style="background-color: #dfd;">s</span>.</span> <br></td></tr>
<tr><td class="diff-unchanged" >** Consistency across components is difficult to maintain, especially when changes to location, replication, etc. occur. <br></td></tr>
<tr><td class="diff-changed-lines" >* <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">Significance</span> <span class="diff-added-words"style="background-color: #dfd;">Benefits</span> <br></td></tr>
<tr><td class="diff-unchanged" >** Encapsulates most of the Ice related "boilerplate code" for Icebox services. <br>** Concrete instance of proper start up and shut down protocol. <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">** Provides some default implementation. <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">** Provides some default implementation, lowering the bar for component developers getting started. <br></td></tr>
<tr><td class="diff-unchanged" >{panel} <br>{color} <br> <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">{color:white} <br>{panel:title=Component Base Class - Features|titleBGColor=#2022FF|bgColor=#7788FF} <br>* Features <br>** Simplifies construction and activation of main objects <br>** Simplifies registration of services with the service locator. <br>{panel} <br>{color} <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">The need for a component base class became increasingly clear as more components were developed. With overall infrastructure-like features like replication, configuration and discovery being added and refined by different developers, the inconsistencies became unmanageable. It was decided to create a base class that would formalize and set in "code" the start-up and shutdown protocols as well as provide support for the implementation of derived classes that provide the component specific specializations. Maintaining the existing components was more efficient and creating new components that behaved as good Asterisk SCF "citizens" was much easier. <br></td></tr>
<tr><td class="diff-unchanged" > <br>{color:white} <br></td></tr>
<tr><td class="diff-changed-lines" >{panel:title=Component Base Class - Anatomy <span class="diff-changed-words">(1/<span class="diff-deleted-chars"style="color:#999;background-color:#fdd;text-decoration:line-through;">2</span><span class="diff-added-chars"style="background-color: #dfd;">3</span>)|titleBGColor=#2022FF|bgColor=#7788FF}</span> <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">* Location <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">{section} <br>{column:width=40%} <br></td></tr>
<tr><td class="diff-changed-lines" >* <span class="diff-changed-words"><span class="diff-deleted-chars"style="color:#999;background-color:#fdd;text-decoration:line-through;">M</span><span class="diff-added-chars"style="background-color: #dfd;">m</span>ethod</span> groups <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">** system component implementation <br></td></tr>
<tr><td class="diff-unchanged" >** initialization <br>** service registration <br>** replication support <br>** shutdown and cleanup <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">{column} <br>{column:width=60%} <br>{code} <br>class ASTSCF_DLL_EXPORT Component : public IceBox::Service <br>{ <br>public: <br> Component(const AsteriskSCF::System::Logging::Logger& logger, <br> const std::string& componentDiscoveryCategory); <br>... <br> void suspended(); <br> void resumed(); <br> void shutdown(); <br>... <br> bool isActive(); <br> void activated(); <br> void standby(); <br>protected: <br>... <br>{code} <br>{column} <br>{section} <br>* Location: <br>** ice-util-cpp/include/AsteriskSCF/Component/Component.h <br>** ice-util-cpp/src/Component/Component.cpp <br></td></tr>
<tr><td class="diff-unchanged" >{panel} <br>{color} <br> <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">After looking at why it exists, let's look at what and where it is. You will notice that the Component class itself is derived from IceBox::Service. Asterisk SCF components are implemented as IceBox services and need to implement certain methods so that IceBox can load, start and stop them properly. The first group of functions: suspended, etc. are there to allow servants implementing the AsteriskSCF "Component" interface defined in Slice to control the IceBox service as well. This interface is accessible remotely through Ice and allows the component to be shutdown or "paused" remotely. The second set of methods are there to support implementations of the Asterisk SCF Replica interface which basically allows a component to be made active or put into standby mode remotely. <br> <br></td></tr>
<tr><td class="diff-unchanged" >{color:white} <br></td></tr>
<tr><td class="diff-changed-lines" >{panel:title=Component Base Class - Anatomy <span class="diff-changed-words">(2/<span class="diff-deleted-chars"style="color:#999;background-color:#fdd;text-decoration:line-through;">2</span><span class="diff-added-chars"style="background-color: #dfd;">3</span>)|titleBGColor=#2022FF|bgColor=#7788FF}</span> <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">{section} <br>{column:width=40%} <br>* Vertical interface methods, i.e. interface for derived classes. <br> <br></td></tr>
<tr><td class="diff-unchanged" >* Default implementations <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">** code snippet for setting up proxies to the locator service. <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;"> <br></td></tr>
<tr><td class="diff-unchanged" >* Abstract (pure virtual) methods. <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">** createPrimaryServices() <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">{column} <br>{column:width=60%} <br>virtual void onPreInitialize() {} <br>virtual void onStart() {} <br>.. <br>void Component::createBackplaneServices() <br>... <br>virtual void createPrimaryServices() = 0; <br>{column} <br>{section} <br></td></tr>
<tr><td class="diff-unchanged" >{panel} <br>{color} <br> <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h1. Notes <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">Most of the rest of the methods are in the "protected" section of the class declaration as they are meant to be used only by derived classes. The methods include "notification" type calls that are called when key stages of initialization or shutdown. For example, onPreInitialize() is where you might initialize third party libraries, etc. Methods like createBackplaneServices() and createPrimaryServices() are key and must have implementations. In the case of backplane services, the minimal set of backplane services are the component and replica objects, so the Component class provides a default implementation. In the case of "primary" services, these are the fundamental services implemented and "advertised" by a particular component instance. It is not possible to provide a default implementation for this method because the objects that need to be created are not known to the Component base class and will change for each component. <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h2. Rationale <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">Amongst the methods not shown here are the important counterparts to initialization, that is the methods that are called when shutting down the components. This is very handy! As they take care of the clean up for you. <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">Components share a common start up and shutdown pattern. <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">{color:white} <br>{panel:title=Component Base Class - Anatomy (3/3)|titleBGColor=#2022FF|bgColor=#7788FF} <br>* Helpers for managing registrations with the service locator <br>** void managePrimaryService(const AsteriskSCF::Discovery::LocatorRegistrationWrapperPtr& service); <br>** void manageBackplaneService(const AsteriskSCF::Discovery::LocatorRegistrationWrapperPtr& service); <br>** AsteriskSCF::Discovery::LocatorRegistrationWrapperPtr <br> wrapServiceForRegistration(const Ice::ObjectPrx& proxy, <br> const std::string& category) const; <br>{panel} <br>{color} <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">Consistency across components is difficult to maintain, especially when changes to location, replication, etc. occur. <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">Finally, here are some examples of some helper methods for registering your services with the service locator and managing the registration, including unregistering the services on shutdown. The first two basically register an instance of a registration wrapper object with one of two collections of wrapper objects. The last method is a little special. It is one of two -- the other one having a few extra parameters -- that "wrap" a proxy with some simple registration information in an object that attempts to contact the service locator and register the proxy so it might be *found* by others. The cool thing is, if it cannot contact the service locator it takes care of retrying it for you. It will keep retrying until you shut down the component. Why is this important? Well, Asterisk SCF is made up of a collection of multiple components, of which the service locator is one. One problem in this type of system is component dependency, particularly on startup. If your component needs another component that is unavailable at startup, you have a few choices, go away, hold things up indefinitely until you can get at that component or continue with initialization, retrying in the background. The first choice is not great because a deployer may pull their hair out trying to figure out why a component is not coming up and waste time checking and re-checking configuration, blaming it on bugs, etc. when all it was that component XYZ was not started yet. The second choice is actually preferred under some conditions, if a component absolutely cannot do anything until it makes that one (or two or three, well you get the idea) important call during startup, then holding up until it can make that call is not always a terrible choice. The third choice is most appropriate when you really should make some calls, but your component could conceivably perform some useful work without it. <br></td></tr>
<tr><td class="diff-unchanged" > <br></td></tr>
<tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h2. Significance <br> <br>Encapsulates most of the Ice related "boilerplate code" for Icebox services. Allowing the developer to get to the actual coding of the component sooner. <br> <br>Concrete instance of proper start up and shut down protocol. <br> <br>h2. Features <br> <br> <br>After building several components, it was apparent that we needed a way to get some consistency in the component initialization code. Since all of the components should perform the same operations, pretty clear patterns emerged and were encapsulated in the *Component Base Class*. In most cases, each Asterisk SCF component should contain a derived <br> <br>The source for the component base class can be found in the ice-util-cpp repository. The header file is include/AsteriskSCF/Component/Component.h and the source file is src/Component/Component.cpp. <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">In Asterisk SCF, the third choice is really very similar to the second one because even if the service comes all the way up, the only way *not* registering with the location (for example) will not affect the overall system function is if none of the other services it is going to call on will need to access it and will do so by finding it through the service locator. _needs rewording.. maybe a diagram would be good... something with a sad face !_ <br></td></tr>
</table>
</div> <h4>Full Content</h4>
<div class="notificationGreySide">
<div class='panelMacro'><table class='warningMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/wiki/images/icons/emoticons/forbidden.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td>Yes, this is written in a very informal, conversational voice. It was easier getting the info out this way.</td></tr></table></div>
<h1><a name="ComponentBaseClass-Slidesuggestions%2Fmockup"></a>Slide suggestions/mockup </h1>
<p><font color="white"><br/>
<div class="panel" style="background-color: #7788FF;border-width: 1px;"><div class="panelHeader" style="border-bottom-width: 1px;background-color: #2022FF;"><b>Component Base Class</b></div><div class="panelContent" style="background-color: #7788FF;">
<ul>
        <li>Rationale
        <ul>
                <li>Components share common start up and shutdown patterns.</li>
                <li>Consistency across components is difficult to maintain, especially when changes to location, replication, etc. occur.</li>
        </ul>
        </li>
        <li>Benefits
        <ul>
                <li>Encapsulates most of the Ice related "boilerplate code" for Icebox services.</li>
                <li>Concrete instance of proper start up and shut down protocol.</li>
                <li>Provides some default implementation, lowering the bar for component developers getting started.</li>
        </ul>
        </li>
</ul>
</div></div></font></p>
<p>The need for a component base class became increasingly clear as more components were developed. With overall infrastructure-like features like replication, configuration and discovery being added and refined by different developers, the inconsistencies became unmanageable. It was decided to create a base class that would formalize and set in "code" the start-up and shutdown protocols as well as provide support for the implementation of derived classes that provide the component specific specializations. Maintaining the existing components was more efficient and creating new components that behaved as good Asterisk SCF "citizens" was much easier.</p>
<p><font color="white"><br/>
<div class="panel" style="background-color: #7788FF;border-width: 1px;"><div class="panelHeader" style="border-bottom-width: 1px;background-color: #2022FF;"><b>Component Base Class - Anatomy (1/3)</b></div><div class="panelContent" style="background-color: #7788FF;">
<table class="sectionMacro" border="0" cellpadding="5" cellspacing="0" width="100%"><tbody><tr>
<td class="confluenceTd" valign="top" width="40%">
<ul>
        <li>method groups
        <ul>
                <li>system component implementation</li>
                <li>initialization</li>
                <li>service registration</li>
                <li>replication support</li>
                <li>shutdown and cleanup</li>
        </ul>
        </li>
</ul>
</td>
<td class="confluenceTd" valign="top" width="60%">
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: java; gutter: false">class ASTSCF_DLL_EXPORT Component : public IceBox::Service
{
public:
Component(const AsteriskSCF::System::Logging::Logger& logger,
const std::string& componentDiscoveryCategory);
...
void suspended();
void resumed();
void shutdown();
...
bool isActive();
void activated();
void standby();
protected:
...</pre>
</div></div></td></tr></tbody></table>
<ul>
        <li>Location:
        <ul>
                <li>ice-util-cpp/include/AsteriskSCF/Component/Component.h</li>
                <li>ice-util-cpp/src/Component/Component.cpp</li>
        </ul>
        </li>
</ul>
</div></div></font></p>
<p>After looking at why it exists, let's look at what and where it is. You will notice that the Component class itself is derived from IceBox::Service. Asterisk SCF components are implemented as IceBox services and need to implement certain methods so that IceBox can load, start and stop them properly. The first group of functions: suspended, etc. are there to allow servants implementing the AsteriskSCF "Component" interface defined in Slice to control the IceBox service as well. This interface is accessible remotely through Ice and allows the component to be shutdown or "paused" remotely. The second set of methods are there to support implementations of the Asterisk SCF Replica interface which basically allows a component to be made active or put into standby mode remotely. </p>
<p><font color="white"><br/>
<div class="panel" style="background-color: #7788FF;border-width: 1px;"><div class="panelHeader" style="border-bottom-width: 1px;background-color: #2022FF;"><b>Component Base Class - Anatomy (2/3)</b></div><div class="panelContent" style="background-color: #7788FF;">
<table class="sectionMacro" border="0" cellpadding="5" cellspacing="0" width="100%"><tbody><tr>
<td class="confluenceTd" valign="top" width="40%">
<ul>
        <li>Vertical interface methods, i.e. interface for derived classes.</li>
</ul>
<ul>
        <li>Default implementations</li>
</ul>
<ul>
        <li>Abstract (pure virtual) methods.</li>
</ul>
</td>
<td class="confluenceTd" valign="top" width="60%">
<p>virtual void onPreInitialize() {}<br/>
virtual void onStart() {}<br/>
..<br/>
void Component::createBackplaneServices() <br/>
...<br/>
virtual void createPrimaryServices() = 0;</p></td></tr></tbody></table>
</div></div></font></p>
<p>Most of the rest of the methods are in the "protected" section of the class declaration as they are meant to be used only by derived classes. The methods include "notification" type calls that are called when key stages of initialization or shutdown. For example, onPreInitialize() is where you might initialize third party libraries, etc. Methods like createBackplaneServices() and createPrimaryServices() are key and must have implementations. In the case of backplane services, the minimal set of backplane services are the component and replica objects, so the Component class provides a default implementation. In the case of "primary" services, these are the fundamental services implemented and "advertised" by a particular component instance. It is not possible to provide a default implementation for this method because the objects that need to be created are not known to the Component base class and will change for each component.</p>
<p>Amongst the methods not shown here are the important counterparts to initialization, that is the methods that are called when shutting down the components. This is very handy! As they take care of the clean up for you.</p>
<p><font color="white"><br/>
<div class="panel" style="background-color: #7788FF;border-width: 1px;"><div class="panelHeader" style="border-bottom-width: 1px;background-color: #2022FF;"><b>Component Base Class - Anatomy (3/3)</b></div><div class="panelContent" style="background-color: #7788FF;">
<ul>
        <li>Helpers for managing registrations with the service locator
        <ul>
                <li>void managePrimaryService(const AsteriskSCF::Discovery::LocatorRegistrationWrapperPtr& service);</li>
                <li>void manageBackplaneService(const AsteriskSCF::Discovery::LocatorRegistrationWrapperPtr& service);</li>
                <li>AsteriskSCF::Discovery::LocatorRegistrationWrapperPtr<br/>
wrapServiceForRegistration(const Ice::ObjectPrx& proxy, <br/>
const std::string& category) const;</li>
        </ul>
        </li>
</ul>
</div></div></font></p>
<p>Finally, here are some examples of some helper methods for registering your services with the service locator and managing the registration, including unregistering the services on shutdown. The first two basically register an instance of a registration wrapper object with one of two collections of wrapper objects. The last method is a little special. It is one of two – the other one having a few extra parameters – that "wrap" a proxy with some simple registration information in an object that attempts to contact the service locator and register the proxy so it might be <b>found</b> by others. The cool thing is, if it cannot contact the service locator it takes care of retrying it for you. It will keep retrying until you shut down the component. Why is this important? Well, Asterisk SCF is made up of a collection of multiple components, of which the service locator is one. One problem in this type of system is component dependency, particularly on startup. If your component needs another component that is unavailable at startup, you have a few choices, go away, hold things up indefinitely until you can get at that component or continue with initialization, retrying in the background. The first choice is not great because a deployer may pull their hair out trying to figure out why a component is not coming up and waste time checking and re-checking configuration, blaming it on bugs, etc. when all it was that component XYZ was not started yet. The second choice is actually preferred under some conditions, if a component absolutely cannot do anything until it makes that one (or two or three, well you get the idea) important call during startup, then holding up until it can make that call is not always a terrible choice. The third choice is most appropriate when you really should make some calls, but your component could conceivably perform some useful work without it. </p>
<p>In Asterisk SCF, the third choice is really very similar to the second one because even if the service comes all the way up, the only way <b>not</b> registering with the location (for example) will not affect the overall system function is if none of the other services it is going to call on will need to access it and will do so by finding it through the service locator. <em>needs rewording.. maybe a diagram would be good... something with a sad face !</em></p>
</div>
<div id="commentsSection" class="wiki-content pageSection">
<div style="float: right;" class="grey">
<a href="https://wiki.asterisk.org/wiki/users/removespacenotification.action?spaceKey=TOP">Stop watching space</a>
<span style="padding: 0px 5px;">|</span>
<a href="https://wiki.asterisk.org/wiki/users/editmyemailsettings.action">Change email notification preferences</a>
</div>
<a href="https://wiki.asterisk.org/wiki/display/TOP/Component+Base+Class">View Online</a>
|
<a href="https://wiki.asterisk.org/wiki/pages/diffpagesbyversion.action?pageId=19006223&revisedVersion=4&originalVersion=3">View Changes</a>
|
<a href="https://wiki.asterisk.org/wiki/display/TOP/Component+Base+Class?showComments=true&showCommentArea=true#addcomment">Add Comment</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>