private void unmanage()

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());
    }