private void doUndeployNetwork(final NetworkConfig network, final Message<JsonObject> message) {
// First we need to load the network's context from the cluster.
final WrappedWatchableMap<String, String> data = new WrappedWatchableMap<String, String>(String.format("%s.%s", cluster, network.getName()), this.data.<String, String>getMap(String.format("%s.%s", cluster, network.getName())), vertx);
String scontext = data.get(String.format("%s.%s", cluster, network.getName()));
if (scontext == null) {
message.reply(new JsonObject().putString("status", "error").putString("message", "Network is not deployed."));
} else {
// Determine whether the network's manager is deployed.
final NetworkContext tempContext = Contexts.<NetworkContext>deserialize(new JsonObject(scontext));
if (managers.containsKey(tempContext.address())) {
// If the network's manager is deployed then unmerge the given
// configuration from the configuration of the network that's
// already running. If the resulting configuration is a no-component
// network then that indicates that the entire network is being undeployed.
// Otherwise, we simply update the existing configuration and allow the
// network's manager to handle deployment and undeployment of components.
NetworkConfig updatedConfig = Configs.unmergeNetworks(tempContext.config(), network);
final NetworkContext context = ContextBuilder.buildContext(updatedConfig, cluster);
// If the new configuration has no components then undeploy the entire network.
if (context.components().isEmpty()) {
// We need to watch the network's status key to determine when the network's
// components have been completely undeployed. Once that happens it's okay
// to then undeploy the network's manager.
data.watch(context.status(), MapEvent.Type.CHANGE, new Handler<MapEvent<String, String>>() {
@Override
public void handle(MapEvent<String, String> event) {
// When the network's status key is set to an empty string, that indicates
// that the network's manager has completely undeployed all components and
// connections within the network. The manager is the only element of the
// network left running, so we can go ahead and undeploy it.
if (event.value() != null && event.value().equals("")) {
// First, stop watching the status key so this handler doesn't accidentally
// get called again for some reason.
data.unwatch(context.status(), MapEvent.Type.CHANGE, this, new Handler<AsyncResult<Void>>() {
@Override
public void handle(AsyncResult<Void> result) {
// Now undeploy the manager from the context cluster. Once the manager
// has been undeployed the undeployment of the network is complete.
platform.undeployVerticle(managers.remove(context.address()), new Handler<AsyncResult<Void>>() {
@Override
public void handle(AsyncResult<Void> result) {
if (result.failed()) {
message.reply(new JsonObject().putString("status", "error").putString("message", result.cause().getMessage()));
} else {
// We can be nice and unset the status key since the manager was undeployed :-)
DefaultNodeManager.this.context.execute(new Action<Void>() {
@Override
public Void perform() {
networks.remove(context.address());
data.remove(context.status());
return null;
}
}, new Handler<AsyncResult<Void>>() {
@Override
public void handle(AsyncResult<Void> result) {
message.reply(new JsonObject().putString("status", "ok"));
}
});
}
}
});
}
});
}
}
}, new Handler<AsyncResult<Void>>() {
@Override
public void handle(AsyncResult<Void> result) {
// Once we've started watching the status key, unset the network's context in
// the cluster. The network's manager will be notified of the configuration
// change and will begin undeploying all of its components. Once the components
// have been undeployed it will reset its status key.
if (result.failed()) {
message.reply(new JsonObject().putString("status", "error").putString("message", result.cause().getMessage()));
} else {
DefaultNodeManager.this.context.run(new Runnable() {
@Override
public void run() {
data.remove(context.address());
}
});
}
}
});
} else {
// If only a portion of the running network is being undeployed, we need
// to watch the network's status key for notification once the configuration
// change is complete.
data.watch(context.status(), MapEvent.Type.CHANGE, new Handler<MapEvent<String, String>>() {
@Override
public void handle(MapEvent<String, String> event) {
if (event.value() != null && event.value().equals(context.version())) {
// The network's configuration has been completely updated. Stop watching
// the network's status key and call the async handler.
data.unwatch(context.status(), null, this, new Handler<AsyncResult<Void>>() {
@Override
public void handle(AsyncResult<Void> result) {
message.reply(new JsonObject().putString("status", "ok").putObject("context", Contexts.serialize(context)));
}
});
}
}
}, new Handler<AsyncResult<Void>>() {
@Override
public void handle(AsyncResult<Void> result) {
// Once we've started watching the status key, update the network's context in
// the cluster. The network's manager will be notified of the configuration
// change and will begin deploying or undeploying components and connections
// as necessary.
if (result.failed()) {
message.reply(new JsonObject().putString("status", "error").putString("message", result.cause().getMessage()));
} else {
DefaultNodeManager.this.context.run(new Runnable() {
@Override
public void run() {
data.put(context.address(), Contexts.serialize(context).encode());
}
});
}
}
});
}
} else {
message.reply(new JsonObject().putString("status", "error").putString("message", "Network is not deployed."));
}
}
}