Component IDL
Code Block |
---|
language | cpp |
---|
title | Async.idl |
---|
linenumbers | true |
---|
collapse | true |
---|
|
#ifndef _ASYNC_IDL_
#define _ASYNC_IDL_
#pragma prefix "acs"
#include <acscommon.idl>
#include <acscomponent.idl>
module examples
{
interface MyCallback: ACS::OffShoot {
void update(in string text);
};
interface Async : ACS::ACSComponent {
oneway void delayAsync(in ACS::uLong delay, in MyCallback cb);
};
interface Async : ACS::ACSComponent {
void delay(in ACS::uLong delay);
};
};
#endif |
Component Implementation
C++
Code Block |
---|
language | cpp |
---|
title | AsyncImpl.h |
---|
linenumbers | true |
---|
collapse | true |
---|
|
#ifndef _ASYNC_IMPL_H
#define _ASYNC_IMPL_H
#include <acscomponentImpl.h>
#include <AsyncS.h>
class AsyncImpl : public virtual acscomponent::ACSComponentImpl, public virtual POA_examples::Async
{
public:
AsyncImpl(const ACE_CString& name, maci::ContainerServices* containerServices);
virtual ~AsyncImpl();
void delayAsync(ACS::uLong delay, acs::examples::MyCallback_ptr cb);
};
#endif
|
Code Block |
---|
language | cpp |
---|
title | AsyncImpl.cpp |
---|
linenumbers | true |
---|
collapse | true |
---|
|
#include <AsyncImpl.h>
#include <ACSErrTypeOK.h>
AsyncImpl::AsyncImpl(const ACE_CString& name, maci::ContainerServices* containerServices) : acscomponent::ACSComponentImpl(name, containerServices) {
}
AsyncImpl::~AsyncImpl() {
}
void AsyncImpl::delayAsync(ACS::uLong delay, acs::examples::MyCallback_ptr cb) {
cb->update("WORKING");
sleep(delay);
cb->update("DONE");
}
/* --------------- [ MACI DLL support functions ] -----------------*/
#include <maciACSComponentDefines.h>
MACI_DLL_SUPPORT_FUNCTIONS(AsyncImpl)
/* ----------------------------------------------------------------*/ |
Configuration
Code Block |
---|
language | xml |
---|
title | Components.xml |
---|
linenumbers | true |
---|
collapse | true |
---|
|
<e Name="ASYNC_CPP"
Code="AsyncImpl"
Type="IDL:acs/examples/Async:1.0"
Container="bilboContainer"
ImplLang="cpp"
KeepAliveTime="0"
/>
<e Name="ASYNC_CLIENT_CPP"
Code="AsyncClientImpl"
Type="IDL:acs/examples/AsyncClient:1.0"
Container="bilboContainer"
ImplLang="cpp"
KeepAliveTime="0"
/> |
Client Implementation
Callback Definition
C++
Code Block |
---|
language | cpp |
---|
title | MyCBImpl.h |
---|
linenumbers | true |
---|
collapse | true |
---|
|
#ifndef _MY_CB_IMPL_H
#define _MY_CB_IMPL_H
#include <AsyncC.h>
class MyCBImpl : public virtual POA_examples::MyCallback {
public:
MyCBImpl() {
status=std::string("INIT");
}
virtual ~CBuLongImpl() {}
void update(const char* value) {
status = std::string(value);
}
public:
std::string status;
};
#endif |
Standalone Client
C++
Code Block |
---|
language | cpp |
---|
title | AsyncClient.cpp |
---|
linenumbers | true |
---|
collapse | true |
---|
|
#include <maciSimpleClient.h>
#include <AsyncC.h>
#include <ACSErrTypeCommon.h>
#include <acsutilTimeStamp.h>
#include <MyCBImpl.h>
using namespace maci;
int main(int argc, char *argv[]) {
SimpleClient client;
examples::Async_var comp;
if (client.init(argc,argv) == 0) {
return -1;
} else {
client.login();
}
try {
comp = client.getComponent<examples::Async>("ASYNC_CPP", 0, true);
} catch(maciErrType::CannotGetComponentExImpl& _ex) {
_ex.log();
return -1;
}
MyCBImpl cb;
examples::MyCallback_var cbObj = cb._this();
ACS_SHORT_LOG((LM_INFO, "%s", cb.status));
comp->delayAsync(8, cbObj.in());
ACS_SHORT_LOG((LM_INFO, "%s", cb.status));
sleep(5);
ACS_SHORT_LOG((LM_INFO, "%s", cb.status));
sleep(5);
ACS_SHORT_LOG((LM_INFO, "%s", cb.status));
try {
client.releaseComponent("ASYNC_CPP");
} catch(maciErrType::CannotReleaseComponentExImpl &_ex) {
_ex.log();
return -1;
}
client.logout();
ACE_OS::sleep(3);
return 0;
} |
Component Client
C++
Code Block |
---|
language | cpp |
---|
title | AsyncClientImpl.h |
---|
linenumbers | true |
---|
collapse | true |
---|
|
#ifndef _ASYNC_CLIENT_IMPL_H
#define _ASYNC_CLIENT_IMPL_H
#include <acscomponentImpl.h>
#include <AsyncS.h>
class AsyncClientImpl : public virtual acscomponent::ACSComponentImpl, public virtual POA_examples::AsyncClient
{
public:
AsyncClientImpl(const ACE_CString& name, maci::ContainerServices* containerServices);
virtual ~AsyncClientImpl();
void delay(ACS::uLong delay);
};
#endif
|
Code Block |
---|
language | cpp |
---|
title | AsyncClientImpl.cpp |
---|
linenumbers | true |
---|
collapse | true |
---|
|
#include <AsyncClientImpl.h>
#include <ACSErrTypeOK.h>
AsyncClientImpl::AsyncClientImpl(const ACE_CString& name, maci::ContainerServices* containerServices) : acscomponent::ACSComponentImpl(name, containerServices) {
}
AsyncClientImpl::~AsyncClientImpl() {
}
void AsyncClientImpl::delay(ACS::uLong delay) {
examples::Async_var comp = getContainerServices().getComponent<examples::Async>("ASYNC_CPP", 0, true);
MyCBImpl cb;
ACS::OffShoot_var offshoot = getContainerServices().activateOffShoot(&cb);
examples::MyCallback_var cbObj = examples::MyCallback::_narrow(offshoot);
ACS_SHORT_LOG((LM_INFO, "%s", cb.status));
comp->delayAsync(delay, cbObj.in());
ACS_SHORT_LOG((LM_INFO, "%s", cb.status));
sleep(delay/2+1);
ACS_SHORT_LOG((LM_INFO, "%s", cb.status));
sleep(delay/2+1);
ACS_SHORT_LOG((LM_INFO, "%s", cb.status));
getContainerServices().releaseComponent("ASYNC_CPP");
getContainerServices().deactivateOffShoot(&cb)
}
/* --------------- [ MACI DLL support functions ] -----------------*/
#include <maciACSComponentDefines.h>
MACI_DLL_SUPPORT_FUNCTIONS(AsyncClientImpl)
/* ----------------------------------------------------------------*/ |
Notes
C++
Standalone Client
When working with standalone clients, we need to handle the servant lifecycle of the offshoots/callbacks. There are two approaches:
- Manual activation/deactivation of the CORBA object
- Manual activation with automatic deactivation of the CORBA object through the POA cleanup process
Manual OffShoot activation/deactivation
This approach is valid both for stack and heap instances of an OffShoot:
Stack OffShoot
For the OffShoot servant instance on the stack, you need to make sure to deactivate the OffShoot servant before cb variable goes out of scope. Here you will get compilation issues if you try to deactivate it after going out of scope.
Code Block |
---|
language | cpp |
---|
linenumbers | true |
---|
collapse | true |
---|
|
MyCBImpl cb;
examples::MyCallback_var cbObj = cb._this();
...
//Deactivate the Offshoot servant
PortableServer::POA_var poa = cb._default_POA();
PortableServer::ObjectId_var id = poa->servant_to_id(&cb);
poa->deactivate_object(id.in()); |
Heap OffShoot
For the OffShoot servant instance on the heap, you need to make sure to deactivate the OffShoot servant before destroying the cb variable. Doing it in the reverse order has undefined behavior, usually ending in segmentation fault.
Code Block |
---|
language | cpp |
---|
linenumbers | true |
---|
collapse | true |
---|
|
MyCBImpl* cb = new MyCBImpl();
examples::MyCallback_var cbObj = cb->_this();
...
//Deactivate the Offshoot servant
PortableServer::POA_var poa = cb->_default_POA();
PortableServer::ObjectId_var id = poa->servant_to_id(cb);
poa->deactivate_object(id.in());
// Make sure to delete the OffShoot servant instance after deactivating the CORBA object
delete cb; |
Manual OffShoot activation with automatic deactivation
This approach is valid both for stack and heap instances of an OffShoot:
Stack OffShoot
For the OffShoot servant instance on the stack, you need to make sure ORB is stopped before cb variable goes out of scope. The variable going out of scope before stopping the ORB is undefined behavior resulting in segmentation fault in most implementations due to trying to access a memory address in a different stack.
Code Block |
---|
language | cpp |
---|
linenumbers | true |
---|
collapse | true |
---|
|
{
MyCBImpl cb;
examples::MyCallback_var cbObj = cb._this();
...
// Stop ORB
...
} |
Heap OffShoot
For the OffShoot servant instance on the heap, you need to make sure to delete the OffShoot servant instance after ORB is stopped. If the variable is deleted before stopping the ORB has undefined behavior, regularly resulting in segmentation fault due to using a destroyed instance.
Code Block |
---|
language | cpp |
---|
linenumbers | true |
---|
collapse | true |
---|
|
MyCBImpl* cb = new MyCBImpl();
examples::MyCallback_var cbObj = cb->_this();
...
// Stop ORB
...
// Delete the heap OffShoot servant instance
delete cb; |
Component Client
When working with standalone clients, we need to handle the servant lifecycle of the offshoots/callbacks. There are three approaches:
...
The first two are very similar to the Standalone Client, but with some caveats that will be explained in the following sections
Manual OffShoot activation/deactivation
The implementation is exactly the same as in the standalone client, the restriction here is just a bit stricter, here we need to deactivate the OffShoot servant before the component is deactivated. It could be part of the method, or be implemented as part of the cleanUp/aboutToAbort component's lifecycle methods, depending on the design decisions. If due to your design it fails to deactivate the OffShoot servant before deactivating the component, then you will get undefined behavior and probably segmentation fault when shutting down the container.
Another downside from this approach is that the ACS developers need to interact directly with CORBA details.
Manual OffShoot activation with automatic deactivation
While technically feasible, there are additional complications to implementing this both for stack and heap OffShoot servant instances. The component is always deactivated before the ORB shuts down, implying that the stack variables will get deleted before the ORB shuts down, resulting in undefined behavior and usually segmentation fault when container is shutting down. It should be possible (although not recommended) to workaround this by storing the servant in global or class variables. For the heap variables, it is possible to skip the deletion of the variable and delegate that to the POA cleanup process.
...
Do not reduce the reference count when using stack OffShoot servant instance as it will trigger double free unexpected behavior (and probably segmentation fault).
Manual Offshoot activation/deactivation using ACS container services
The idea behind this approach is very similar to point 1. with manual OffShoot activation/deactivation, however there are two benefits:
...