Archived

This forum has been archived. Please start a new discussion on GitHub.

IceGrid sessions, Glacier2 and factory objects?

Working with Glacier2 is still puzzling me. Any help is greatly appreciated.
As a variation on the IceGrid/"sayHello()" example, I extended the Demo module with a "HelloFactory":
module Demo
{
interface Hello {
["cpp:const"] idempotent string sayHello();
void shutdown();
};
interface HelloFactory {
["cpp:const"] Hello* createHello( string name );
};
};
On the server side, I created a Hello object and a HelloFactory object, which I both made available as allocatable to the icegrid session. So there are two ways to say hello: either via a call "sayHello()" directly on the allocated "Hello" object, or via a call to a freshly created Hello object from the allocated factory.

Here comes my problem:
Without using the Glacier2 router, both ways work as expected. However, with the Glacier2 router in place, the sayHello() call directly on the allocated Hello object still works, but the alternative via the factory yields an exception:
Outgoing.cpp:388: Ice::ObjectNotExistException:
object does not exist:
identity: `CCBF3961-B714-47D1-88AA-808A2DD75BFC'
facet:
operation: sayHello
What am I doing wrong?
Below follow some details

On the client, a session is obtained via
if(communicator()->getDefaultRouter())
{
Ice::RouterPrx defaultRouter = communicator()->getDefaultRouter();
_router = Glacier2::RouterPrx::checkedCast(defaultRouter);
_session = IceGrid::SessionPrx::checkedCast(_router->createSession( "foo", "bar" ));
}
else
{
IceGrid::RegistryPrx registry = IceGrid::RegistryPrx::checkedCast(
communicator()->stringToProxy("DemoIceGrid/Registry"));
_session = registry->createSession( "foo", "bar" );
}
where the branch is selected by setting either
Ice.Default.Router=Allocate.Glacier2/router:tcp -p 12001
(use glacier2: only works partially) or
Ice.Default.Locator=DemoIceGrid/Locator:default -p 12000
(no glacier2: ok!) in the client configuration file.
Also on the client, I select between the direct approach and the factory using a boolean "withFactory":
HelloPrx hello;

if (withFactory)
{
HelloFactoryPrx hf = HelloFactoryPrx::checkedCast(_session->allocateObjectByType("::Demo::HelloFactory"));
hello = hf->createHello( "<foo>" );
}
else
{
hello = HelloPrx::checkedCast(_session->allocateObjectByType("::Demo::Hello"));
}

hello->sayHello();

Finally,
The server side implementation looks like:
int Server::run(int, char* [])
{
Ice::PropertiesPtr properties = communicator()->getProperties();
Ice::ObjectAdapterPtr adapter = communicator()->createObjectAdapter("Hello");

std::string srvId = properties->getProperty("Ice.ServerId");
Ice::Identity id = communicator()->stringToIdentity(properties->getProperty("Identity"));
adapter->add( new HelloI( srvId ), id );

id = communicator()->stringToIdentity(properties->getProperty("Identity2"));
adapter->add( new HelloFactoryI, id );

adapter->activate();
communicator()->waitForShutdown();
return EXIT_SUCCESS;
}

The descriptor file reads:
<icegrid>
<application name="Allocate">
<server-template id="AllocateServer">
<parameter name="index"/>
<server id="AllocateServer-${index}" exe="/home/bertwim/develop/gapps/Linux-2.6/benoitS" activation="on-demand">
<adapter name="Hello" endpoints="tcp" register-process="true">
<allocatable identity="hello-${index}" type="::Demo::Hello" property="Identity"/>
<allocatable identity="hf-${index}" type="::Demo::HelloFactory" property="Identity2"/>
</adapter>
</server>
</server-template>
<server-template id="Glacier2">
<parameter name="instance-name" default="${application}.Glacier2"/>
<parameter name="client-endpoints"/>
<parameter name="server-endpoints"/>
<parameter name="session-timeout" default="30"/>
<server id="${instance-name}" exe="glacier2router" activation="always">
<properties>
<property name="Glacier2.Client.Endpoints" value="${client-endpoints}"/>
<property name="Glacier2.Server.Endpoints" value="${server-endpoints}"/>
<property name="Glacier2.Admin.Endpoints" value="tcp -h 127.0.0.1"/>
<property name="Glacier2.Admin.RegisterProcess" value="1"/>
<property name="Glacier2.InstanceName" value="${instance-name}"/>
<property name="Glacier2.SessionTimeout" value="${session-timeout}"/>
<property name="Glacier2.PermissionsVerifier" value="${instance-name}/NullPermissionsVerifier"/>
<property name="Glacier2.SessionManager" value="DemoIceGrid/SessionManager"/>
</properties>
</server>
</server-template>
<node name="localhost">
<server-instance template="AllocateServer" index="1"/>
<server-instance template="AllocateServer" index="2"/>
<server-instance template="Glacier2" client-endpoints="tcp -p 12001" server-endpoints="tcp"/>
</node>
</application>
</icegrid>

Comments

  • matthew
    matthew NL, Canada
    I suspect what is going on is the Glacier2 filtering rules are kicking in and denying access to the factory created hello object. To fix this issue you need to add the identity of the allocated object to the Glacier2 identity filter. You can see the Ice manual for full details on this. I also recommend you read my article "Custom Sessions and IceGrid" in issue 19 of the Connections newsletter for an example.
  • benoit
    benoit Rennes, France
    As Matthew pointed out, the problem is most likely that Glacier2 filtering only allows invocations on allocated objects (see 38.14.3 Allocating Servers and Objects).

    To allow your client to access objects created by the factory, you can interpose a session like described by Matthew's article from the Connections newsletter issue #19. This interposed session will allow you to disable the default filtering or to add your own filtering.

    Another option is to mark the server as allocatable by adding allocatable="true" to the XML server element. With this attribute set, the allocation of the factory object will cause the allocation of the server and will alter the Glacier2 filtering to allow invocations on the objects from the "Hello" object adapter of the allocated server.

    Cheers,
    Benoit.
  • The allocatable="true" hint you gave worked.
    Thanks.