summaryrefslogtreecommitdiff
path: root/cpp
diff options
context:
space:
mode:
authorBenoit Foucher <benoit@zeroc.com>2007-06-12 15:42:23 +0200
committerBenoit Foucher <benoit@zeroc.com>2007-06-12 15:42:23 +0200
commit607a0c7f320dacb590d0816ab0b121a2b6c784e7 (patch)
treec576a0ab9e31b1e57f66c4a85c457331e1889230 /cpp
parentSupport for Sun Studio 12 (CC 5.9) (diff)
downloadice-607a0c7f320dacb590d0816ab0b121a2b6c784e7.tar.bz2
ice-607a0c7f320dacb590d0816ab0b121a2b6c784e7.tar.xz
ice-607a0c7f320dacb590d0816ab0b121a2b6c784e7.zip
Fixed bug 2220
Diffstat (limited to 'cpp')
-rw-r--r--cpp/CHANGES5
-rw-r--r--cpp/src/IceGrid/AdapterCache.cpp36
-rw-r--r--cpp/src/IceGrid/AdapterCache.h1
-rw-r--r--cpp/src/IceGrid/Database.cpp101
-rw-r--r--cpp/src/IceGrid/Database.h3
-rw-r--r--cpp/src/IceGrid/DescriptorHelper.cpp90
-rw-r--r--cpp/src/IceGrid/DescriptorHelper.h6
-rw-r--r--cpp/test/IceGrid/replicaGroup/AllTests.cpp151
8 files changed, 380 insertions, 13 deletions
diff --git a/cpp/CHANGES b/cpp/CHANGES
index 52926d60a6e..1a9d6f785e5 100644
--- a/cpp/CHANGES
+++ b/cpp/CHANGES
@@ -1,6 +1,10 @@
Changes since version 3.2.X (binary incompabible)
-------------------------------------------------
+- IceGrid now allows defining an object adapter with a replica group
+ from an other IceGrid application than the one where the object
+ adapter is defined.
+
- Added a new method to the ObjectAdapter interface named
refreshPublishedEndpoints(). This method is meant to be used to
update the published endpoints after change in the available local
@@ -2752,3 +2756,4 @@ Changes since version 1.0.0
- Several other changes that make Ice for C++ more portable.
- Updated SSL test certificates. The old ones have expired.
+
diff --git a/cpp/src/IceGrid/AdapterCache.cpp b/cpp/src/IceGrid/AdapterCache.cpp
index a16d205c425..e3bf7562803 100644
--- a/cpp/src/IceGrid/AdapterCache.cpp
+++ b/cpp/src/IceGrid/AdapterCache.cpp
@@ -93,7 +93,11 @@ AdapterCache::addServerAdapter(const AdapterDescriptor& desc, const ServerEntryP
if(!desc.replicaGroupId.empty())
{
ReplicaGroupEntryPtr repEntry = ReplicaGroupEntryPtr::dynamicCast(getImpl(desc.replicaGroupId));
- assert(repEntry);
+ if(!repEntry)
+ {
+ Ice::Error out(_communicator->getLogger());
+ out << "can't add adapter `" << desc.id << "' to unknown replica group `" << desc.replicaGroupId << "'";
+ }
repEntry->addReplica(desc.id, entry);
}
}
@@ -142,7 +146,11 @@ AdapterCache::removeServerAdapter(const string& id)
if(!replicaGroupId.empty())
{
ReplicaGroupEntryPtr repEntry = ReplicaGroupEntryPtr::dynamicCast(getImpl(replicaGroupId));
- assert(repEntry);
+ if(!repEntry)
+ {
+ Ice::Error out(_communicator->getLogger());
+ out << "can't remove adapter `" << id << "' from unknown replica group `" << replicaGroupId << "'";
+ }
repEntry->removeReplica(id);
}
}
@@ -483,6 +491,10 @@ ReplicaGroupEntry::getLeastLoadedNodeLoad(LoadSample loadSample) const
AdapterInfoSeq
ReplicaGroupEntry::getAdapterInfo() const
{
+ //
+ // This method is called with the database locked so we're sure
+ // that no new adapters will be added or removed concurrently.
+ //
vector<ServerAdapterEntryPtr> replicas;
{
Lock sync(*this);
@@ -498,3 +510,23 @@ ReplicaGroupEntry::getAdapterInfo() const
}
return infos;
}
+
+bool
+ReplicaGroupEntry::hasAdaptersFromOtherApplications() const
+{
+ vector<ServerAdapterEntryPtr> replicas;
+ {
+ Lock sync(*this);
+ replicas = _replicas;
+ }
+
+ AdapterInfoSeq infos;
+ for(vector<ServerAdapterEntryPtr>::const_iterator p = replicas.begin(); p != replicas.end(); ++p)
+ {
+ if((*p)->getApplication() != _application)
+ {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/cpp/src/IceGrid/AdapterCache.h b/cpp/src/IceGrid/AdapterCache.h
index 451b434f2b4..cddd18b7f72 100644
--- a/cpp/src/IceGrid/AdapterCache.h
+++ b/cpp/src/IceGrid/AdapterCache.h
@@ -97,6 +97,7 @@ public:
void removeReplica(const std::string&);
void update(const LoadBalancingPolicyPtr&);
+ bool hasAdaptersFromOtherApplications() const;
private:
diff --git a/cpp/src/IceGrid/Database.cpp b/cpp/src/IceGrid/Database.cpp
index 264580a1236..6281eaa1c0f 100644
--- a/cpp/src/IceGrid/Database.cpp
+++ b/cpp/src/IceGrid/Database.cpp
@@ -487,13 +487,21 @@ Database::removeApplication(const string& name, AdminSessionI* session)
throw ApplicationNotExistException(name);
}
+ bool init = false;
try
{
ApplicationHelper helper(_communicator, p->second.descriptor);
+ init = true;
+ checkForRemove(helper);
unload(helper, entries);
}
catch(const DeploymentException&)
{
+ if(init)
+ {
+ throw;
+ }
+
//
// For some reasons the application became invalid. If
// it's invalid, it's most likely not loaded either. So we
@@ -1216,6 +1224,11 @@ Database::checkForAddition(const ApplicationHelper& app)
for_each(serverIds.begin(), serverIds.end(), objFunc(*this, &Database::checkServerForAddition));
for_each(adapterIds.begin(), adapterIds.end(), objFunc(*this, &Database::checkAdapterForAddition));
for_each(objectIds.begin(), objectIds.end(), objFunc(*this, &Database::checkObjectForAddition));
+
+ set<string> repGrps;
+ set<string> adptRepGrps;
+ app.getReplicaGroups(repGrps, adptRepGrps);
+ for_each(adptRepGrps.begin(), adptRepGrps.end(), objFunc(*this, &Database::checkReplicaGroupExists));
}
void
@@ -1233,12 +1246,45 @@ Database::checkForUpdate(const ApplicationHelper& origApp, const ApplicationHelp
for_each(addedSvrs.begin(), addedSvrs.end(), objFunc(*this, &Database::checkServerForAddition));
Ice::StringSeq addedAdpts;
- set_difference(newAdpts.begin(), newAdpts.end(), oldAdpts.begin(), oldAdpts.end(), set_inserter(addedAdpts));
+ set_difference(newAdpts.begin(), newAdpts.end(), oldAdpts.begin(), oldAdpts.end(), back_inserter(addedAdpts));
for_each(addedAdpts.begin(), addedAdpts.end(), objFunc(*this, &Database::checkAdapterForAddition));
vector<Ice::Identity> addedObjs;
- set_difference(newObjs.begin(), newObjs.end(), oldObjs.begin(), oldObjs.end(), set_inserter(addedObjs));
+ set_difference(newObjs.begin(), newObjs.end(), oldObjs.begin(), oldObjs.end(), back_inserter(addedObjs));
for_each(addedObjs.begin(), addedObjs.end(), objFunc(*this, &Database::checkObjectForAddition));
+
+ set<string> oldRepGrps, newRepGrps;
+ set<string> oldAdptRepGrps, newAdptRepGrps;
+ origApp.getReplicaGroups(oldRepGrps, oldAdptRepGrps);
+ newApp.getReplicaGroups(newRepGrps, newAdptRepGrps);
+
+ set<string> rmRepGrps;
+ set_difference(oldRepGrps.begin(), oldRepGrps.end(), newRepGrps.begin(),newRepGrps.end(), set_inserter(rmRepGrps));
+ for_each(rmRepGrps.begin(), rmRepGrps.end(), objFunc(*this, &Database::checkReplicaGroupForRemove));
+
+ set<string> addedAdptRepGrps;
+ set_difference(newAdptRepGrps.begin(),newAdptRepGrps.end(), oldAdptRepGrps.begin(), oldAdptRepGrps.end(),
+ set_inserter(addedAdptRepGrps));
+ for_each(addedAdptRepGrps.begin(), addedAdptRepGrps.end(), objFunc(*this, &Database::checkReplicaGroupExists));
+
+ vector<string> invalidAdptRepGrps;
+ set_intersection(rmRepGrps.begin(), rmRepGrps.end(), newAdptRepGrps.begin(), newAdptRepGrps.end(),
+ back_inserter(invalidAdptRepGrps));
+ if(!invalidAdptRepGrps.empty())
+ {
+ DeploymentException ex;
+ ex.reason = "couldn't find replica group `" + invalidAdptRepGrps.front() + "'";
+ throw ex;
+ }
+}
+
+void
+Database::checkForRemove(const ApplicationHelper& app)
+{
+ set<string> replicaGroups;
+ set<string> adapterReplicaGroups;
+ app.getReplicaGroups(replicaGroups, adapterReplicaGroups);
+ for_each(replicaGroups.begin(), replicaGroups.end(), objFunc(*this, &Database::checkReplicaGroupForRemove));
}
void
@@ -1279,6 +1325,57 @@ Database::checkObjectForAddition(const Ice::Identity& objectId)
}
void
+Database::checkReplicaGroupExists(const string& replicaGroup)
+{
+ ReplicaGroupEntryPtr entry;
+ try
+ {
+ entry = ReplicaGroupEntryPtr::dynamicCast(_adapterCache.get(replicaGroup));
+ }
+ catch(const AdapterNotExistException&)
+ {
+ }
+
+ if(!entry)
+ {
+ DeploymentException ex;
+ ex.reason = "couldn't find replica group `" + replicaGroup + "'";
+ throw ex;
+ }
+}
+
+void
+Database::checkReplicaGroupForRemove(const string& replicaGroup)
+{
+ ReplicaGroupEntryPtr entry;
+ try
+ {
+ entry = ReplicaGroupEntryPtr::dynamicCast(_adapterCache.get(replicaGroup));
+ }
+ catch(const AdapterNotExistException&)
+ {
+ }
+
+ if(!entry)
+ {
+ //
+ // This would indicate an inconsistency with the cache and
+ // database. We don't print an error, it will be printed
+ // when the application is actually removed.
+ //
+ return;
+ }
+
+ if(entry->hasAdaptersFromOtherApplications())
+ {
+ DeploymentException ex;
+ ex.reason = "couldn't remove application because the replica group `" + replicaGroup +
+ "' is used by object adapters from other applications.";
+ throw ex;
+ }
+}
+
+void
Database::load(const ApplicationHelper& app, ServerEntrySeq& entries, const string& uuid, int revision)
{
const NodeDescriptorDict& nodes = app.getInstance().nodes;
diff --git a/cpp/src/IceGrid/Database.h b/cpp/src/IceGrid/Database.h
index a02bbe02eb2..bee84509cee 100644
--- a/cpp/src/IceGrid/Database.h
+++ b/cpp/src/IceGrid/Database.h
@@ -124,10 +124,13 @@ private:
void checkForAddition(const ApplicationHelper&);
void checkForUpdate(const ApplicationHelper&, const ApplicationHelper&);
+ void checkForRemove(const ApplicationHelper&);
void checkServerForAddition(const std::string&);
void checkAdapterForAddition(const std::string&);
void checkObjectForAddition(const Ice::Identity&);
+ void checkReplicaGroupExists(const std::string&);
+ void checkReplicaGroupForRemove(const std::string&);
void load(const ApplicationHelper&, ServerEntrySeq&, const std::string&, int);
void unload(const ApplicationHelper&, ServerEntrySeq&);
diff --git a/cpp/src/IceGrid/DescriptorHelper.cpp b/cpp/src/IceGrid/DescriptorHelper.cpp
index 57a5b0c5641..c41aa5c04de 100644
--- a/cpp/src/IceGrid/DescriptorHelper.cpp
+++ b/cpp/src/IceGrid/DescriptorHelper.cpp
@@ -977,6 +977,18 @@ CommunicatorHelper::getIds(multiset<string>& adapterIds, multiset<Ice::Identity>
}
}
+void
+CommunicatorHelper::getReplicaGroups(set<string>& replicaGroups) const
+{
+ for(AdapterDescriptorSeq::const_iterator p = _desc->adapters.begin(); p != _desc->adapters.end(); ++p)
+ {
+ if(!p->replicaGroupId.empty())
+ {
+ replicaGroups.insert(p->replicaGroupId);
+ }
+ }
+}
+
void
CommunicatorHelper::instantiateImpl(const CommunicatorDescriptorPtr& instance, const Resolver& resolve) const
{
@@ -992,10 +1004,18 @@ CommunicatorHelper::instantiateImpl(const CommunicatorDescriptorPtr& instance, c
adapter.registerProcess = p->registerProcess;
adapter.serverLifetime = p->serverLifetime;
adapter.replicaGroupId = resolve.asId(p->replicaGroupId, "object adapter replica group id", true);
- if(!adapter.replicaGroupId.empty() && !resolve.hasReplicaGroup(adapter.replicaGroupId))
- {
- resolve.exception("unknown replica group `" + adapter.replicaGroupId + "'");
- }
+
+ //
+ // Don't check for unknown replica groups here. This check is
+ // instead done by the database before the application is
+ // added. It's legal for an OA to refer to a replica group
+ // from another application.
+ //
+ //if(!adapter.replicaGroupId.empty() && !resolve.hasReplicaGroup(adapter.replicaGroupId))
+ //{
+ //resolve.exception("unknown replica group `" + adapter.replicaGroupId + "'");
+ //}
+
adapter.priority = resolve.asInt(p->priority, "object adapter priority");
adapter.objects = resolve(p->objects, "well-known");
adapter.allocatables = resolve(p->allocatables, "allocatable");
@@ -1505,6 +1525,16 @@ IceBoxHelper::getIds(multiset<string>& adapterIds, multiset<Ice::Identity>& obje
}
void
+IceBoxHelper::getReplicaGroups(set<string>& replicaGroups) const
+{
+ CommunicatorHelper::getReplicaGroups(replicaGroups);
+ for(vector<ServiceInstanceHelper>::const_iterator p = _services.begin(); p != _services.end(); ++p)
+ {
+ p->getReplicaGroups(replicaGroups);
+ }
+}
+
+void
IceBoxHelper::print(const Ice::CommunicatorPtr& communicator, Output& out) const
{
print(communicator, out, ServerInfo());
@@ -1694,6 +1724,13 @@ ServiceInstanceHelper::getIds(multiset<string>& adapterIds, multiset<Ice::Identi
}
void
+ServiceInstanceHelper::getReplicaGroups(set<string>& replicaGroups) const
+{
+ assert(_service.getDescriptor());
+ _service.getReplicaGroups(replicaGroups);
+}
+
+void
ServiceInstanceHelper::print(const Ice::CommunicatorPtr& communicator, Output& out) const
{
if(_service.getDescriptor())
@@ -1875,6 +1912,13 @@ ServerInstanceHelper::getIds(multiset<string>& adapterIds, multiset<Ice::Identit
_serverInstance->getIds(adapterIds, objectIds);
}
+void
+ServerInstanceHelper::getReplicaGroups(set<string>& replicaGroups) const
+{
+ assert(_serverInstance);
+ _serverInstance->getReplicaGroups(replicaGroups);
+}
+
NodeHelper::NodeHelper(const string& name,
const NodeDescriptor& descriptor,
const Resolver& appResolve,
@@ -2137,6 +2181,21 @@ NodeHelper::getIds(multiset<string>& serverIds, multiset<string>& adapterIds, mu
}
}
+void
+NodeHelper::getReplicaGroups(set<string>& replicaGroups) const
+{
+ assert(_instantiated);
+ ServerInstanceHelperDict::const_iterator p;
+ for(p = _serverInstances.begin(); p != _serverInstances.end(); ++p)
+ {
+ p->second.getReplicaGroups(replicaGroups);
+ }
+ for(p = _servers.begin(); p != _servers.end(); ++p)
+ {
+ p->second.getReplicaGroups(replicaGroups);
+ }
+}
+
const NodeDescriptor&
NodeHelper::getDefinition() const
{
@@ -2700,6 +2759,29 @@ ApplicationHelper::getIds(set<string>& serverIds, set<string>& adapterIds, set<I
copy(oIds.begin(), oIds.end(), inserter(objectIds, objectIds.begin()));
}
+void
+ApplicationHelper::getReplicaGroups(set<string>& replicaGroups, set<string>& adapterReplicaGroups) const
+{
+ ReplicaGroupDescriptorSeq::const_iterator r;
+ for(r = _def.replicaGroups.begin(); r != _def.replicaGroups.end(); ++r)
+ {
+ replicaGroups.insert(r->id);
+ }
+
+ set<string> allAdapterReplicaGroups;
+ for(NodeHelperDict::const_iterator p = _nodes.begin(); p != _nodes.end(); ++p)
+ {
+ p->second.getReplicaGroups(allAdapterReplicaGroups);
+ }
+
+ //
+ // Only return references to replica groups which don't belong to
+ // this application.
+ //
+ set_difference(allAdapterReplicaGroups.begin(), allAdapterReplicaGroups.end(),
+ replicaGroups.begin(), replicaGroups.end(), set_inserter(adapterReplicaGroups));
+}
+
const ApplicationDescriptor&
ApplicationHelper::getDefinition() const
{
diff --git a/cpp/src/IceGrid/DescriptorHelper.h b/cpp/src/IceGrid/DescriptorHelper.h
index cbc9da7ce60..e222940686c 100644
--- a/cpp/src/IceGrid/DescriptorHelper.h
+++ b/cpp/src/IceGrid/DescriptorHelper.h
@@ -90,6 +90,7 @@ public:
bool operator!=(const CommunicatorHelper&) const;
virtual void getIds(std::multiset<std::string>&, std::multiset<Ice::Identity>&) const;
+ virtual void getReplicaGroups(std::set<std::string>&) const;
void print(const Ice::CommunicatorPtr&, IceUtil::Output&) const;
@@ -184,6 +185,7 @@ public:
ServiceInstanceDescriptor instantiate(const Resolver&, const PropertySetDescriptorDict&) const;
void getIds(std::multiset<std::string>&, std::multiset<Ice::Identity>&) const;
+ void getReplicaGroups(std::set<std::string>&) const;
void print(const Ice::CommunicatorPtr&, IceUtil::Output&) const;
@@ -208,6 +210,7 @@ public:
const PropertySetDescriptorDict&) const;
virtual void getIds(std::multiset<std::string>&, std::multiset<Ice::Identity>&) const;
+ virtual void getReplicaGroups(std::set<std::string>&) const;
void print(const Ice::CommunicatorPtr&, IceUtil::Output&) const;
void print(const Ice::CommunicatorPtr&, IceUtil::Output&, const ServerInfo&) const;
@@ -243,6 +246,7 @@ public:
ServerDescriptorPtr getServerInstance() const;
void getIds(std::multiset<std::string>&, std::multiset<Ice::Identity>&) const;
+ void getReplicaGroups(std::set<std::string>&) const;
private:
@@ -270,6 +274,7 @@ public:
NodeDescriptor update(const NodeUpdateDescriptor&, const Resolver&) const;
void getIds(std::multiset<std::string>&, std::multiset<std::string>&, std::multiset<Ice::Identity>&) const;
+ void getReplicaGroups(std::set<std::string>&) const;
const NodeDescriptor& getDefinition() const;
const NodeDescriptor& getInstance() const;
void getServerInfos(const std::string&, const std::string&, int, std::map<std::string, ServerInfo>&) const;
@@ -304,6 +309,7 @@ public:
ApplicationDescriptor instantiateServer(const std::string&, const ServerInstanceDescriptor&) const;
void getIds(std::set<std::string>&, std::set<std::string>&, std::set<Ice::Identity>&) const;
+ void getReplicaGroups(std::set<std::string>&, std::set<std::string>&) const;
const ApplicationDescriptor& getDefinition() const;
const ApplicationDescriptor& getInstance() const;
void getDistributions(DistributionDescriptor&, std::vector<std::string>&,const std::string& = std::string()) const;
diff --git a/cpp/test/IceGrid/replicaGroup/AllTests.cpp b/cpp/test/IceGrid/replicaGroup/AllTests.cpp
index 5e101fbf023..1bef85f3b3d 100644
--- a/cpp/test/IceGrid/replicaGroup/AllTests.cpp
+++ b/cpp/test/IceGrid/replicaGroup/AllTests.cpp
@@ -73,7 +73,8 @@ private:
typedef IceUtil::Handle<SessionKeepAliveThread> SessionKeepAliveThreadPtr;
void
-instantiateServer(const AdminPrx& admin, const string& templ, const string& node, const map<string, string>& params)
+instantiateServer(const AdminPrx& admin, const string& templ, const string& node, const map<string, string>& params,
+ const string& application = string("Test"))
{
ServerInstanceDescriptor desc;
desc._cpp_template = templ;
@@ -82,17 +83,22 @@ instantiateServer(const AdminPrx& admin, const string& templ, const string& node
nodeUpdate.name = node;
nodeUpdate.serverInstances.push_back(desc);
ApplicationUpdateDescriptor update;
- update.name = "Test";
+ update.name = application;
update.nodes.push_back(nodeUpdate);
try
{
admin->updateApplication(update);
}
- catch(DeploymentException& ex)
+ catch(const DeploymentException& ex)
{
cerr << ex.reason << endl;
test(false);
}
+ catch(const Ice::LocalException& ex)
+ {
+ cerr << ex << endl;
+ test(false);
+ }
}
void
@@ -114,11 +120,13 @@ removeServer(const AdminPrx& admin, const string& id)
test(false);
}
+ ServerInfo info = admin->getServerInfo(id);
+
NodeUpdateDescriptor nodeUpdate;
- nodeUpdate.name = "localnode";
+ nodeUpdate.name = info.node;
nodeUpdate.removeServers.push_back(id);
ApplicationUpdateDescriptor update;
- update.name = "Test";
+ update.name = info.application;
update.nodes.push_back(nodeUpdate);
try
{
@@ -593,6 +601,139 @@ allTests(const Ice::CommunicatorPtr& comm)
};
cout << "ok" << endl;
+ cout << "testing replica group from different applications... " << flush;
+ {
+ map<string, string> params;
+ params["replicaGroup"] = "Random";
+ params["id"] = "Server1";
+ instantiateServer(admin, "Server", "localnode", params);
+
+ ApplicationUpdateDescriptor update;
+ update.name = "Test";
+ update.removeReplicaGroups.push_back("Random");
+ try
+ {
+ admin->updateApplication(update);
+ test(false);
+ }
+ catch(const DeploymentException&)
+ {
+ // The Random replica goup is used by Server1!
+ }
+
+ //
+ // Add an application Test1 without replica groups and a
+ // server that uses the Random replica group.
+ //
+ ApplicationInfo app = admin->getApplicationInfo("Test");
+ app.descriptor.name = "Test1";
+ app.descriptor.replicaGroups.clear();
+ app.descriptor.nodes.clear();
+ try
+ {
+ admin->addApplication(app.descriptor);
+ }
+ catch(const DeploymentException& ex)
+ {
+ cerr << ex << endl;
+ test(false);
+ }
+ params["id"] = "Server2";
+ instantiateServer(admin, "Server", "localnode", params, "Test1");
+
+ try
+ {
+ admin->removeApplication("Test");
+ test(false);
+ }
+ catch(const DeploymentException&)
+ {
+ // Test has a replica group referenced by the Test1 application.
+ }
+
+ TestIntfPrx obj = TestIntfPrx::uncheckedCast(comm->stringToProxy("Random"));
+ obj = TestIntfPrx::uncheckedCast(obj->ice_locatorCacheTimeout(0));
+ obj = TestIntfPrx::uncheckedCast(obj->ice_connectionCached(false));
+ set<string> replicaIds;
+ replicaIds.insert("Server1.ReplicatedAdapter");
+ replicaIds.insert("Server2.ReplicatedAdapter");
+ while(!replicaIds.empty())
+ {
+ try
+ {
+ replicaIds.erase(obj->getReplicaId());
+ }
+ catch(const Ice::LocalException& ex)
+ {
+ cerr << ex << endl;
+ test(false);
+ }
+ }
+
+ removeServer(admin, "Server2");
+ removeServer(admin, "Server1");
+
+ ReplicaGroupDescriptor replicaGroup;
+ replicaGroup.id = "ReplicatedAdapterFromTest1";
+ replicaGroup.loadBalancing = new RandomLoadBalancingPolicy();
+ replicaGroup.loadBalancing->nReplicas = "0";
+ update = ApplicationUpdateDescriptor();
+ update.name = "Test1";
+ update.replicaGroups.push_back(replicaGroup);
+
+ try
+ {
+ admin->updateApplication(update);
+ }
+ catch(const DeploymentException& ex)
+ {
+ cerr << ex.reason << endl;
+ test(false);
+ }
+
+ params["replicaGroup"] = "ReplicatedAdapterFromTest1";
+ params["id"] = "Server1";
+ instantiateServer(admin, "Server", "localnode", params);
+
+ try
+ {
+ admin->removeApplication("Test1");
+ test(false);
+ }
+ catch(const DeploymentException&)
+ {
+ // ReplicatedAdapterFromTest1 used by server from Test
+ }
+
+ update = ApplicationUpdateDescriptor();
+ update.name = "Test1";
+ update.removeReplicaGroups.push_back("ReplicatedAdapterFromTest1");
+ try
+ {
+ admin->updateApplication(update);
+ test(false);
+ }
+ catch(const DeploymentException&)
+ {
+ // ReplicatedAdapterFromTest1 used by server from Test
+ }
+
+ removeServer(admin, "Server1");
+
+ try
+ {
+ admin->updateApplication(update);
+ }
+ catch(const DeploymentException& ex)
+ {
+ cerr << ex << endl;
+ test(false);
+ }
+
+ admin->removeApplication("Test1");
+ };
+ cout << "ok" << endl;
+
keepAlive->destroy();
keepAlive->getThreadControl().join();
keepAlive = 0;