in core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalEntityManager.java [535:656]
private void unmanage(final Entity e, ManagementTransitionMode mode, boolean hasBeenReplaced) {
if (shouldSkipUnmanagement(e, hasBeenReplaced)) return;
final ManagementTransitionInfo info = new ManagementTransitionInfo(managementContext, mode);
log.debug("Unmanaging "+e+" (mode "+mode+", replaced "+hasBeenReplaced+")");
if (hasBeenReplaced) {
// we are unmanaging an old instance after having replaced it
// don't unmanage or even clear its fields, because there might be references to it
if (mode.wasReadOnly()) {
// if coming *from* read only; nothing needed
} else {
if (!mode.wasPrimary()) {
log.warn("Unexpected mode "+mode+" for unmanage-replace "+e+" (applying anyway)");
}
// migrating away or in-place active partial rebind:
((EntityInternal)e).getManagementSupport().onManagementStopping(info, false);
stopTasks(e);
((EntityInternal)e).getManagementSupport().onManagementStopped(info, false);
}
// do not remove from maps below, bail out now
return;
} else if (mode.wasReadOnly() && mode.isNoLongerLoaded()) {
// we are unmanaging an instance (secondary); either stopping here or primary destroyed elsewhere
((EntityInternal)e).getManagementSupport().onManagementStopping(info, false);
if (unmanageNonRecursive(e)) {
stopTasks(e);
}
((EntityInternal)e).getManagementSupport().onManagementStopped(info, false);
managementContext.getRebindManager().getChangeListener().onUnmanaged(e);
if (managementContext.getGarbageCollector() != null) managementContext.getGarbageCollector().onUnmanaged(e);
} else if (mode.wasPrimary() && mode.isNoLongerLoaded()) {
// unmanaging a primary; currently this is done recursively
/* TODO tidy up when it is recursive and when it isn't; if something is being unloaded or destroyed,
* that probably *is* recursive, but the old mode might be different if in some cases things are read-only.
* or maybe nothing needs to be recursive, we just make sure the callers (e.g. HighAvailabilityModeImpl.clearManagedItems)
* call in a good order
*
* see notes above about recursive/manage/All/unmanageAll
*/
// Need to store all child entities as onManagementStopping removes a child from the parent entity
final Set<EntityInternal> allEntities = new LinkedHashSet<>();
int iteration = 0;
do {
List<Entity> entitiesToUnmanageRecursively = MutableList.of();
if (iteration>0) {
log.info("Re-running descendant unmanagement on descendants of "+e+" which were added concurrently during previous iteration: "+allEntities);
if (iteration>=20) throw new IllegalStateException("Too many iterations detected trying to unmanage descendants of "+e+" ("+iteration+")");
entitiesToUnmanageRecursively.addAll(allEntities);
} else {
entitiesToUnmanageRecursively.add(e);
}
entitiesToUnmanageRecursively.forEach(ei -> recursively(ei, new Predicate<EntityInternal>() {
@Override
public boolean apply(EntityInternal it) {
if (shouldSkipUnmanagement(it, false)) return false;
allEntities.add(it);
it.getManagementSupport().onManagementStopping(info, false);
return true;
}
}));
if (!allEntities.isEmpty()) {
MutableList<EntityInternal> allEntitiesExceptApp = MutableList.copyOf(allEntities);
EntityInternal app = allEntitiesExceptApp.remove(0);
Collections.reverse(allEntitiesExceptApp);
// log in reverse order, so that ancestor nodes logged later because they are more interesting
// (and application is the last one logged)
allEntitiesExceptApp.forEach(it -> {
BrooklynLoggingCategories.ENTITY_LIFECYCLE_LOG.debug("Deleting entity " + it.getId() + " (" + it + ") in application " + it.getApplicationId() + " for user " + Entitlements.getEntitlementContextUser());
});
BrooklynLoggingCategories.APPLICATION_LIFECYCLE_LOG.debug("Deleting application " + app.getId() + " (" + app + ") mode " + mode + " for user " + Entitlements.getEntitlementContextUser());
}
for (EntityInternal it : allEntities) {
if (shouldSkipUnmanagement(it, false)) continue;
if (unmanageNonRecursive(it)) {
stopTasks(it);
}
}
for (EntityInternal it : allEntities) {
it.getManagementSupport().onManagementStopped(info, false);
managementContext.getRebindManager().getChangeListener().onUnmanaged(it);
if (managementContext.getGarbageCollector() != null)
managementContext.getGarbageCollector().onUnmanaged(e);
}
// re-run in case a child has been added
final Set<EntityInternal> allEntitiesAgain = new LinkedHashSet<>();
// here loop through each entity because the children will normally be cleared during unmanagement
allEntities.forEach(ei -> recursively(ei, new Predicate<EntityInternal>() {
@Override
public boolean apply(EntityInternal it) {
allEntitiesAgain.add(it);
return true;
}
}));
allEntitiesAgain.removeAll(allEntities);
allEntities.clear();
allEntities.addAll(allEntitiesAgain);
iteration++;
} while (!allEntities.isEmpty());
} else {
log.warn("Invalid mode for unmanage: "+mode+" on "+e+" (ignoring)");
}
preRegisteredEntitiesById.remove(e.getId());
preManagedEntitiesById.remove(e.getId());
entityProxiesById.remove(e.getId());
entitiesById.remove(e.getId());
entityModesById.remove(e.getId());
}