http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityChangeListener.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityChangeListener.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityChangeListener.java deleted file mode 100644 index b7f53a4..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityChangeListener.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.core.mgmt.internal; - -import org.apache.brooklyn.api.effector.Effector; -import org.apache.brooklyn.api.policy.Policy; -import org.apache.brooklyn.api.sensor.AttributeSensor; -import org.apache.brooklyn.api.sensor.Enricher; -import org.apache.brooklyn.api.sensor.Feed; -import org.apache.brooklyn.config.ConfigKey; - -public interface EntityChangeListener { - - // TODO for testing only! - public static final EntityChangeListener NOOP = new EntityChangeListener() { - @Override public void onChanged() {} - @Override public void onAttributeChanged(AttributeSensor<?> attribute) {} - @Override public void onConfigChanged(ConfigKey<?> key) {} - @Override public void onLocationsChanged() {} - @Override public void onMembersChanged() {} - @Override public void onTagsChanged() {} - @Override public void onChildrenChanged() {} - @Override public void onPolicyAdded(Policy policy) {} - @Override public void onPolicyRemoved(Policy policy) {} - @Override public void onEnricherAdded(Enricher enricher) {} - @Override public void onEnricherRemoved(Enricher enricher) {} - @Override public void onFeedAdded(Feed feed) {} - @Override public void onFeedRemoved(Feed feed) {} - @Override public void onEffectorStarting(Effector<?> effector, Object parameters) {} - @Override public void onEffectorCompleted(Effector<?> effector) {} - }; - - void onChanged(); - - void onAttributeChanged(AttributeSensor<?> attribute); - - void onConfigChanged(ConfigKey<?> key); - - void onLocationsChanged(); - - void onTagsChanged(); - - void onMembersChanged(); - - void onChildrenChanged(); - - void onPolicyAdded(Policy policy); - - void onPolicyRemoved(Policy policy); - - void onEnricherAdded(Enricher enricher); - - void onEnricherRemoved(Enricher enricher); - - void onFeedAdded(Feed feed); - - void onFeedRemoved(Feed feed); - - void onEffectorStarting(Effector<?> effector, Object parameters); - - void onEffectorCompleted(Effector<?> effector); -}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagementSupport.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagementSupport.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagementSupport.java deleted file mode 100644 index 3811542..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagementSupport.java +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.core.mgmt.internal; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.brooklyn.api.effector.Effector; -import org.apache.brooklyn.api.entity.Application; -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.mgmt.ExecutionContext; -import org.apache.brooklyn.api.mgmt.ManagementContext; -import org.apache.brooklyn.api.mgmt.SubscriptionContext; -import org.apache.brooklyn.api.mgmt.entitlement.EntitlementManager; -import org.apache.brooklyn.api.policy.Policy; -import org.apache.brooklyn.api.sensor.AttributeSensor; -import org.apache.brooklyn.api.sensor.Enricher; -import org.apache.brooklyn.api.sensor.Feed; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.entity.AbstractEntity; -import org.apache.brooklyn.core.entity.Entities; -import org.apache.brooklyn.core.entity.EntityInternal; -import org.apache.brooklyn.core.mgmt.entitlement.Entitlements; -import org.apache.brooklyn.core.mgmt.entitlement.Entitlements.EntityAndItem; -import org.apache.brooklyn.core.mgmt.entitlement.Entitlements.StringAndArgument; -import org.apache.brooklyn.core.mgmt.internal.NonDeploymentManagementContext.NonDeploymentManagementContextMode; -import org.apache.brooklyn.util.exceptions.Exceptions; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.annotations.Beta; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; -import com.google.common.base.Stopwatch; - -/** - * Encapsulates management activities at an entity. - * <p> - * On entity deployment, ManagementContext.manage(entity) causes - * <p> - * * onManagementStarting(ManagementContext) - * * onManagementStartingSubscriptions() - * * onManagementStartingSensorEmissions() - * * onManagementStartingExecutions() - * * onManagementStarted() - when all the above is said and done - * * onManagementStartingHere(); - * <p> - * on unmanage it hits onManagementStoppingHere() then onManagementStopping(). - * <p> - * When an entity's management migrates, it invokes onManagementStoppingHere() at the old location, - * then onManagementStartingHere() at the new location. - */ -public class EntityManagementSupport { - - private static final Logger log = LoggerFactory.getLogger(EntityManagementSupport.class); - - public EntityManagementSupport(AbstractEntity entity) { - this.entity = entity; - nonDeploymentManagementContext = new NonDeploymentManagementContext(entity, NonDeploymentManagementContextMode.PRE_MANAGEMENT); - } - - protected transient AbstractEntity entity; - NonDeploymentManagementContext nonDeploymentManagementContext; - - protected transient ManagementContext initialManagementContext; - protected transient ManagementContext managementContext; - protected transient SubscriptionContext subscriptionContext; - protected transient ExecutionContext executionContext; - - protected final AtomicBoolean managementContextUsable = new AtomicBoolean(false); - protected final AtomicBoolean currentlyDeployed = new AtomicBoolean(false); - protected final AtomicBoolean everDeployed = new AtomicBoolean(false); - protected Boolean readOnly = null; - protected final AtomicBoolean managementFailed = new AtomicBoolean(false); - - private volatile EntityChangeListener entityChangeListener = EntityChangeListener.NOOP; - - /** - * Whether this entity is managed (i.e. "onManagementStarting" has been called, so the framework knows about it, - * and it has not been unmanaged). - */ - public boolean isDeployed() { - return currentlyDeployed.get(); - } - - public boolean isNoLongerManaged() { - return wasDeployed() && !isDeployed(); - } - - /** whether entity has ever been deployed (managed) */ - public boolean wasDeployed() { - return everDeployed.get(); - } - - @Beta - public void setReadOnly(boolean isReadOnly) { - if (isDeployed()) - throw new IllegalStateException("Cannot set read only after deployment"); - this.readOnly = isReadOnly; - } - - /** Whether the entity and its adjuncts should be treated as read-only; - * may be null briefly when initializing if RO status is unknown. */ - @Beta - public Boolean isReadOnlyRaw() { - return readOnly; - } - - /** Whether the entity and its adjuncts should be treated as read-only; - * error if initializing and RO status is unknown. */ - @Beta - public boolean isReadOnly() { - Preconditions.checkNotNull(readOnly, "Read-only status of %s not yet known", entity); - return readOnly; - } - - /** - * Whether the entity's management lifecycle is complete (i.e. both "onManagementStarting" and "onManagementStarted" have - * been called, and it is has not been unmanaged). - */ - public boolean isFullyManaged() { - return (nonDeploymentManagementContext == null) && currentlyDeployed.get(); - } - - public synchronized void setManagementContext(ManagementContextInternal val) { - if (initialManagementContext != null) { - throw new IllegalStateException("Initial management context is already set for "+entity+"; cannot change"); - } - if (managementContext != null && !managementContext.equals(val)) { - throw new IllegalStateException("Management context is already set for "+entity+"; cannot change"); - } - - this.initialManagementContext = checkNotNull(val, "managementContext"); - if (nonDeploymentManagementContext != null) { - nonDeploymentManagementContext.setManagementContext(val); - } - } - - public void onRebind(ManagementTransitionInfo info) { - nonDeploymentManagementContext.setMode(NonDeploymentManagementContextMode.MANAGEMENT_REBINDING); - } - - public void onManagementStarting(ManagementTransitionInfo info) { - try { - synchronized (this) { - boolean alreadyManaging = isDeployed(); - - if (alreadyManaging) { - log.warn("Already managed: "+entity+" ("+nonDeploymentManagementContext+"); onManagementStarting is no-op"); - } else if (nonDeploymentManagementContext == null || !nonDeploymentManagementContext.getMode().isPreManaged()) { - throw new IllegalStateException("Not in expected pre-managed state: "+entity+" ("+nonDeploymentManagementContext+")"); - } - if (managementContext != null && !managementContext.equals(info.getManagementContext())) { - throw new IllegalStateException("Already has management context: "+managementContext+"; can't set "+info.getManagementContext()); - } - if (initialManagementContext != null && !initialManagementContext.equals(info.getManagementContext())) { - throw new IllegalStateException("Already has different initial management context: "+initialManagementContext+"; can't set "+info.getManagementContext()); - } - if (alreadyManaging) { - return; - } - - this.managementContext = info.getManagementContext(); - nonDeploymentManagementContext.setMode(NonDeploymentManagementContextMode.MANAGEMENT_STARTING); - - if (!isReadOnly()) { - nonDeploymentManagementContext.getSubscriptionManager().setDelegate((AbstractSubscriptionManager) managementContext.getSubscriptionManager()); - nonDeploymentManagementContext.getSubscriptionManager().startDelegatingForSubscribing(); - } - - managementContextUsable.set(true); - currentlyDeployed.set(true); - everDeployed.set(true); - - entityChangeListener = new EntityChangeListenerImpl(); - } - - /* - * TODO framework starting events - phase 1, including rebind - * - establish hierarchy (child, groups, etc; construction if necessary on rebind) - * - set location - * - set local config values - * - set saved sensor values - * - register subscriptions -- BUT nothing is allowed to execute - * [these operations may be done before we invoke starting also; above can happen in any order; - * sensor _publications_ and executor submissions are queued] - * then: set the management context and the entity is "managed" from the perspective of external viewers (ManagementContext.isManaged(entity) returns true) - */ - - if (!isReadOnly()) { - entity.onManagementStarting(); - } - } catch (Throwable t) { - managementFailed.set(true); - throw Exceptions.propagate(t); - } - } - - @SuppressWarnings("deprecation") - public void onManagementStarted(ManagementTransitionInfo info) { - try { - synchronized (this) { - boolean alreadyManaged = isFullyManaged(); - - if (alreadyManaged) { - log.warn("Already managed: "+entity+" ("+nonDeploymentManagementContext+"); onManagementStarted is no-op"); - } else if (nonDeploymentManagementContext == null || nonDeploymentManagementContext.getMode() != NonDeploymentManagementContextMode.MANAGEMENT_STARTING) { - throw new IllegalStateException("Not in expected \"management starting\" state: "+entity+" ("+nonDeploymentManagementContext+")"); - } - if (managementContext != info.getManagementContext()) { - throw new IllegalStateException("Already has management context: "+managementContext+"; can't set "+info.getManagementContext()); - } - if (alreadyManaged) { - return; - } - - nonDeploymentManagementContext.setMode(NonDeploymentManagementContextMode.MANAGEMENT_STARTED); - - /* - * - set derived/inherited config values - * - publish all queued sensors - * - start all queued executions (e.g. subscription delivery) - * [above happens in exactly this order, at each entity] - * then: the entity internally knows it fully managed (ManagementSupport.isManaged() returns true -- though not sure we need that); - * subsequent sensor events and executions occur directly (no queueing) - */ - - if (!isReadOnly()) { - nonDeploymentManagementContext.getSubscriptionManager().startDelegatingForPublishing(); - } - - // TODO more of the above - // TODO custom started activities - // (elaborate or remove ^^^ ? -AH, Sept 2014) - } - - if (!isReadOnly()) { - entity.onManagementBecomingMaster(); - entity.onManagementStarted(); - } - - synchronized (this) { - nonDeploymentManagementContext = null; - } - } catch (Throwable t) { - managementFailed.set(true); - throw Exceptions.propagate(t); - } - } - - @SuppressWarnings("deprecation") - public void onManagementStopping(ManagementTransitionInfo info) { - synchronized (this) { - if (managementContext != info.getManagementContext()) { - throw new IllegalStateException("onManagementStopping encountered different management context for "+entity+ - (!wasDeployed() ? " (wasn't deployed)" : !isDeployed() ? " (no longer deployed)" : "")+ - ": "+managementContext+"; expected "+info.getManagementContext()+" (may be a pre-registered entity which was never properly managed)"); - } - Stopwatch startTime = Stopwatch.createStarted(); - while (!managementFailed.get() && nonDeploymentManagementContext!=null && - nonDeploymentManagementContext.getMode()==NonDeploymentManagementContextMode.MANAGEMENT_STARTING) { - // still becoming managed - try { - if (startTime.elapsed(TimeUnit.SECONDS) > 30) { - // emergency fix, 30s timeout for management starting - log.error("Management stopping event "+info+" in "+this+" timed out waiting for start; proceeding to stopping"); - break; - } - wait(100); - } catch (InterruptedException e) { - Exceptions.propagate(e); - } - } - if (nonDeploymentManagementContext==null) { - nonDeploymentManagementContext = new NonDeploymentManagementContext(entity, NonDeploymentManagementContextMode.MANAGEMENT_STOPPING); - } else { - // already stopped? or not started? - nonDeploymentManagementContext.setMode(NonDeploymentManagementContextMode.MANAGEMENT_STOPPING); - } - } - // TODO custom stopping activities - // TODO framework stopping events - no more sensors, executions, etc - // (elaborate or remove ^^^ ? -AH, Sept 2014) - - if (!isReadOnly() && info.getMode().isDestroying()) { - // if we support remote parent of local child, the following call will need to be properly remoted - if (entity.getParent()!=null) entity.getParent().removeChild(entity.getProxyIfAvailable()); - } - // new subscriptions will be queued / not allowed - nonDeploymentManagementContext.getSubscriptionManager().stopDelegatingForSubscribing(); - // new publications will be queued / not allowed - nonDeploymentManagementContext.getSubscriptionManager().stopDelegatingForPublishing(); - - if (!isReadOnly()) { - entity.onManagementNoLongerMaster(); - entity.onManagementStopped(); - } - } - - public void onManagementStopped(ManagementTransitionInfo info) { - synchronized (this) { - if (managementContext == null && nonDeploymentManagementContext.getMode() == NonDeploymentManagementContextMode.MANAGEMENT_STOPPED) { - return; - } - if (managementContext != info.getManagementContext()) { - throw new IllegalStateException("Has different management context: "+managementContext+"; expected "+info.getManagementContext()); - } - getSubscriptionContext().unsubscribeAll(); - entityChangeListener = EntityChangeListener.NOOP; - managementContextUsable.set(false); - currentlyDeployed.set(false); - executionContext = null; - subscriptionContext = null; - } - - // TODO framework stopped activities, e.g. serialize state ? - entity.invalidateReferences(); - - synchronized (this) { - managementContext = null; - nonDeploymentManagementContext.setMode(NonDeploymentManagementContextMode.MANAGEMENT_STOPPED); - } - } - - @VisibleForTesting - @Beta - public boolean isManagementContextReal() { - return managementContextUsable.get(); - } - - public synchronized ManagementContext getManagementContext() { - return (managementContextUsable.get()) ? managementContext : nonDeploymentManagementContext; - } - - public synchronized ExecutionContext getExecutionContext() { - if (executionContext!=null) return executionContext; - if (managementContextUsable.get()) { - executionContext = managementContext.getExecutionContext(entity); - return executionContext; - } - return nonDeploymentManagementContext.getExecutionContext(entity); - } - public synchronized SubscriptionContext getSubscriptionContext() { - if (subscriptionContext!=null) return subscriptionContext; - if (managementContextUsable.get()) { - subscriptionContext = managementContext.getSubscriptionContext(entity); - return subscriptionContext; - } - return nonDeploymentManagementContext.getSubscriptionContext(entity); - } - public synchronized EntitlementManager getEntitlementManager() { - return getManagementContext().getEntitlementManager(); - } - - public void attemptLegacyAutodeployment(String effectorName) { - synchronized (this) { - if (managementContext != null) { - log.warn("Autodeployment suggested but not required for " + entity + "." + effectorName); - return; - } - if (entity instanceof Application) { - log.warn("Autodeployment with new management context triggered for " + entity + "." + effectorName + " -- will not be supported in future. Explicit manage call required."); - if (initialManagementContext != null) { - initialManagementContext.getEntityManager().manage(entity); - } else { - Entities.startManagement(entity); - } - return; - } - } - if ("start".equals(effectorName)) { - Entity e=entity; - if (e.getParent()!=null && ((EntityInternal)e.getParent()).getManagementSupport().isDeployed()) { - log.warn("Autodeployment in parent's management context triggered for "+entity+"."+effectorName+" -- will not be supported in future. Explicit manage call required."); - ((EntityInternal)e.getParent()).getManagementContext().getEntityManager().manage(entity); - return; - } - } - log.warn("Autodeployment not available for "+entity+"."+effectorName); - } - - public EntityChangeListener getEntityChangeListener() { - return entityChangeListener; - } - - private class EntityChangeListenerImpl implements EntityChangeListener { - @Override - public void onChanged() { - getManagementContext().getRebindManager().getChangeListener().onChanged(entity); - } - @Override - public void onChildrenChanged() { - getManagementContext().getRebindManager().getChangeListener().onChanged(entity); - } - @Override - public void onLocationsChanged() { - getManagementContext().getRebindManager().getChangeListener().onChanged(entity); - } - @Override - public void onTagsChanged() { - getManagementContext().getRebindManager().getChangeListener().onChanged(entity); - } - @Override - public void onMembersChanged() { - getManagementContext().getRebindManager().getChangeListener().onChanged(entity); - } - @Override - public void onPolicyAdded(Policy policy) { - getManagementContext().getRebindManager().getChangeListener().onChanged(entity); - getManagementContext().getRebindManager().getChangeListener().onManaged(policy); - } - @Override - public void onEnricherAdded(Enricher enricher) { - getManagementContext().getRebindManager().getChangeListener().onChanged(entity); - getManagementContext().getRebindManager().getChangeListener().onManaged(enricher); - } - @Override - public void onFeedAdded(Feed feed) { - getManagementContext().getRebindManager().getChangeListener().onChanged(entity); - getManagementContext().getRebindManager().getChangeListener().onManaged(feed); - } - @Override - public void onPolicyRemoved(Policy policy) { - getManagementContext().getRebindManager().getChangeListener().onChanged(entity); - getManagementContext().getRebindManager().getChangeListener().onUnmanaged(policy); - } - @Override - public void onEnricherRemoved(Enricher enricher) { - getManagementContext().getRebindManager().getChangeListener().onChanged(entity); - getManagementContext().getRebindManager().getChangeListener().onUnmanaged(enricher); - } - @Override - public void onFeedRemoved(Feed feed) { - getManagementContext().getRebindManager().getChangeListener().onChanged(entity); - getManagementContext().getRebindManager().getChangeListener().onUnmanaged(feed); - } - @Override - public void onAttributeChanged(AttributeSensor<?> attribute) { - // TODO Could make this more efficient by inspecting the attribute to decide if needs persisted - // immediately, or not important, or transient (e.g. do we really need to persist - // request-per-second count for rebind purposes?!) - getManagementContext().getRebindManager().getChangeListener().onChanged(entity); - } - @Override - public void onConfigChanged(ConfigKey<?> key) { - getManagementContext().getRebindManager().getChangeListener().onChanged(entity); - } - @Override - public void onEffectorStarting(Effector<?> effector, Object parameters) { - Entitlements.checkEntitled(getEntitlementManager(), Entitlements.INVOKE_EFFECTOR, EntityAndItem.of(entity, StringAndArgument.of(effector.getName(), parameters))); - } - @Override - public void onEffectorCompleted(Effector<?> effector) { - getManagementContext().getRebindManager().getChangeListener().onChanged(entity); - } - } - - @Override - public String toString() { - return super.toString()+"["+(entity==null ? "null" : entity.getId())+"]"; - } -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagerInternal.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagerInternal.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagerInternal.java deleted file mode 100644 index 7bad213..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/EntityManagerInternal.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.core.mgmt.internal; - -import org.apache.brooklyn.api.entity.Application; -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.mgmt.EntityManager; - -public interface EntityManagerInternal extends EntityManager, BrooklynObjectManagerInternal<Entity> { - - /** gets all entities currently known to the application, including entities that are not yet managed */ - Iterable<Entity> getAllEntitiesInApplication(Application application); - - public Iterable<String> getEntityIds(); - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/ExternalConfigSupplierRegistry.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/ExternalConfigSupplierRegistry.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/ExternalConfigSupplierRegistry.java deleted file mode 100644 index 81f0ee3..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/ExternalConfigSupplierRegistry.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.core.mgmt.internal; - -import org.apache.brooklyn.core.config.external.ExternalConfigSupplier; - -import com.google.common.annotations.Beta; - - -/** - * Permits a number of {@link ExternalConfigSupplier} instances to be registered, each with a unique name, for future - * (deferred) lookup of configuration values. - * - * @since 0.8.0 - */ -@Beta -public interface ExternalConfigSupplierRegistry { - - void addProvider(String name, ExternalConfigSupplier provider); - void removeProvider(String name); - - /** - * Searches the named {@link ExternalConfigSupplier} for the config value associated with the specified key. - * Quietly returns <code>null</code> if no config exists for the specified key. - * Throws {@link IllegalArgumentException} if no {@link ExternalConfigSupplier} exists for the passed name. - */ - public String getConfig(String providerName, String key); - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/GroovyObservablesPropertyChangeToCollectionChangeAdapter.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/GroovyObservablesPropertyChangeToCollectionChangeAdapter.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/GroovyObservablesPropertyChangeToCollectionChangeAdapter.java deleted file mode 100644 index cd13e1c..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/GroovyObservablesPropertyChangeToCollectionChangeAdapter.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.core.mgmt.internal; - -import groovy.util.ObservableList; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; - -public class GroovyObservablesPropertyChangeToCollectionChangeAdapter implements PropertyChangeListener { - @SuppressWarnings("rawtypes") - private final CollectionChangeListener delegate; - - public GroovyObservablesPropertyChangeToCollectionChangeAdapter(@SuppressWarnings("rawtypes") CollectionChangeListener delegate) { - this.delegate = delegate; - } - - @SuppressWarnings("unchecked") - public void propertyChange(PropertyChangeEvent evt) { - if (evt instanceof ObservableList.ElementAddedEvent) { - delegate.onItemAdded(evt.getNewValue()); - } else if (evt instanceof ObservableList.ElementRemovedEvent) { - delegate.onItemRemoved(evt.getOldValue()); - } else if (evt instanceof ObservableList.ElementUpdatedEvent) { - delegate.onItemRemoved(evt.getOldValue()); - delegate.onItemAdded(evt.getNewValue()); - } else if (evt instanceof ObservableList.ElementClearedEvent) { - for (Object value : ((ObservableList.ElementClearedEvent) evt).getValues()) { - delegate.onItemAdded(value); - } - } else if(evt instanceof ObservableList.MultiElementAddedEvent ) { - for(Object value: ((ObservableList.MultiElementAddedEvent)evt).getValues()){ - delegate.onItemAdded(value); - } - } - } - - public int hashCode() { - return delegate.hashCode(); - } - - public boolean equals(Object other) { - if (other instanceof GroovyObservablesPropertyChangeToCollectionChangeAdapter) - return delegate.equals(((GroovyObservablesPropertyChangeToCollectionChangeAdapter) other).delegate); - if (other instanceof CollectionChangeListener) - return delegate.equals(other); - return false; - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalAccessManager.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalAccessManager.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalAccessManager.java deleted file mode 100644 index 1780972..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalAccessManager.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.core.mgmt.internal; - -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.location.Location; -import org.apache.brooklyn.api.mgmt.AccessController; - -import com.google.common.annotations.Beta; - -@Beta -public class LocalAccessManager implements AccessManager { - - private volatile boolean locationProvisioningAllowed = true; - private volatile boolean locationManagementAllowed = true; - private volatile boolean entityManagementAllowed = true; - - private final AtomicReference<AccessControllerImpl> controller = new AtomicReference<AccessControllerImpl>(); - - public LocalAccessManager() { - updateAccessController(); - } - - @Override - public AccessController getAccessController() { - return controller.get(); - } - - @Override - public boolean isLocationProvisioningAllowed() { - return locationProvisioningAllowed; - } - - @Override - public boolean isLocationManagementAllowed() { - return locationManagementAllowed; - } - - @Override - public boolean isEntityManagementAllowed() { - return entityManagementAllowed; - } - - @Override - public void setLocationProvisioningAllowed(boolean allowed) { - locationProvisioningAllowed = allowed; - updateAccessController(); - } - - @Override - public void setLocationManagementAllowed(boolean allowed) { - locationManagementAllowed = allowed; - updateAccessController(); - } - - @Override - public void setEntityManagementAllowed(boolean allowed) { - entityManagementAllowed = allowed; - updateAccessController(); - } - - private void updateAccessController() { - controller.set(new AccessControllerImpl(locationProvisioningAllowed, locationManagementAllowed, entityManagementAllowed)); - } - - private static class AccessControllerImpl implements AccessController { - private final boolean locationProvisioningAllowed; - private final boolean locationManagementAllowed; - private final boolean entityManagementAllowed; - - public AccessControllerImpl(boolean locationProvisioningAllowed, boolean locationManagementAllowed, - boolean entityManagementAllowed) { - this.locationProvisioningAllowed = locationProvisioningAllowed; - this.locationManagementAllowed = locationManagementAllowed; - this.entityManagementAllowed = entityManagementAllowed; - } - - @Override - public Response canProvisionLocation(Location provisioner) { - return (locationProvisioningAllowed ? Response.allowed() : Response.disallowed("location provisioning disabled")); - } - - @Override - public Response canManageLocation(Location loc) { - return (locationManagementAllowed ? Response.allowed() : Response.disallowed("location management disabled")); - } - - @Override - public Response canManageEntity(Entity entity) { - return (entityManagementAllowed ? Response.allowed() : Response.disallowed("entity management disabled")); - } - } -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalEntityManager.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalEntityManager.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalEntityManager.java deleted file mode 100644 index aaa12d5..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalEntityManager.java +++ /dev/null @@ -1,820 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.core.mgmt.internal; - -import static com.google.common.base.Preconditions.checkNotNull; -import groovy.util.ObservableList; - -import java.lang.reflect.Proxy; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.WeakHashMap; -import java.util.concurrent.ConcurrentMap; - -import javax.annotation.Nullable; - -import org.apache.brooklyn.api.entity.Application; -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.entity.EntitySpec; -import org.apache.brooklyn.api.entity.EntityTypeRegistry; -import org.apache.brooklyn.api.entity.Group; -import org.apache.brooklyn.api.mgmt.AccessController; -import org.apache.brooklyn.api.mgmt.Task; -import org.apache.brooklyn.api.policy.Policy; -import org.apache.brooklyn.api.policy.PolicySpec; -import org.apache.brooklyn.api.sensor.Enricher; -import org.apache.brooklyn.api.sensor.EnricherSpec; -import org.apache.brooklyn.core.BrooklynLogging; -import org.apache.brooklyn.core.entity.AbstractEntity; -import org.apache.brooklyn.core.entity.Entities; -import org.apache.brooklyn.core.entity.EntityInternal; -import org.apache.brooklyn.core.entity.EntityPredicates; -import org.apache.brooklyn.core.entity.trait.Startable; -import org.apache.brooklyn.core.internal.storage.BrooklynStorage; -import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; -import org.apache.brooklyn.core.objs.BasicEntityTypeRegistry; -import org.apache.brooklyn.core.objs.proxy.EntityProxy; -import org.apache.brooklyn.core.objs.proxy.EntityProxyImpl; -import org.apache.brooklyn.core.objs.proxy.InternalEntityFactory; -import org.apache.brooklyn.core.objs.proxy.InternalPolicyFactory; -import org.apache.brooklyn.util.collections.MutableSet; -import org.apache.brooklyn.util.collections.SetFromLiveMap; -import org.apache.brooklyn.util.core.task.Tasks; -import org.apache.brooklyn.util.exceptions.Exceptions; -import org.apache.brooklyn.util.time.CountdownTimer; -import org.apache.brooklyn.util.time.Duration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.annotations.Beta; -import com.google.common.base.Function; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - -public class LocalEntityManager implements EntityManagerInternal { - - private static final Logger log = LoggerFactory.getLogger(LocalEntityManager.class); - - private final LocalManagementContext managementContext; - private final BasicEntityTypeRegistry entityTypeRegistry; - private final InternalEntityFactory entityFactory; - private final InternalPolicyFactory policyFactory; - - /** Entities that have been created, but have not yet begun to be managed */ - protected final Map<String,Entity> preRegisteredEntitiesById = Collections.synchronizedMap(new WeakHashMap<String, Entity>()); - - /** Entities that are in the process of being managed, but where management is not yet complete */ - protected final Map<String,Entity> preManagedEntitiesById = Collections.synchronizedMap(new WeakHashMap<String, Entity>()); - - /** Proxies of the managed entities */ - protected final ConcurrentMap<String,Entity> entityProxiesById = Maps.newConcurrentMap(); - - /** Real managed entities */ - protected final Map<String,Entity> entitiesById = Maps.newLinkedHashMap(); - - /** Management mode for each entity */ - protected final Map<String,ManagementTransitionMode> entityModesById = Collections.synchronizedMap(Maps.<String,ManagementTransitionMode>newLinkedHashMap()); - - /** Proxies of the managed entities */ - protected final ObservableList entities = new ObservableList(); - - /** Proxies of the managed entities that are applications */ - protected final Set<Application> applications = Sets.newConcurrentHashSet(); - - private final BrooklynStorage storage; - private final Map<String,String> entityTypes; - private final Set<String> applicationIds; - - public LocalEntityManager(LocalManagementContext managementContext) { - this.managementContext = checkNotNull(managementContext, "managementContext"); - this.storage = managementContext.getStorage(); - this.entityTypeRegistry = new BasicEntityTypeRegistry(); - this.policyFactory = new InternalPolicyFactory(managementContext); - this.entityFactory = new InternalEntityFactory(managementContext, entityTypeRegistry, policyFactory); - - entityTypes = storage.getMap("entities"); - applicationIds = SetFromLiveMap.create(storage.<String,Boolean>getMap("applications")); - } - - public InternalEntityFactory getEntityFactory() { - if (!isRunning()) throw new IllegalStateException("Management context no longer running"); - return entityFactory; - } - - public InternalPolicyFactory getPolicyFactory() { - if (!isRunning()) throw new IllegalStateException("Management context no longer running"); - return policyFactory; - } - - @Override - public EntityTypeRegistry getEntityTypeRegistry() { - if (!isRunning()) throw new IllegalStateException("Management context no longer running"); - return entityTypeRegistry; - } - - @SuppressWarnings("unchecked") - @Override - public <T extends Entity> T createEntity(EntitySpec<T> spec) { - try { - T entity = entityFactory.createEntity(spec); - Entity proxy = ((AbstractEntity)entity).getProxy(); - checkNotNull(proxy, "proxy for entity %s, spec %s", entity, spec); - - manage(entity); - - return (T) proxy; - } catch (Throwable e) { - log.warn("Failed to create entity using spec "+spec+" (rethrowing)", e); - throw Exceptions.propagate(e); - } - } - - @Override - public <T extends Entity> T createEntity(Map<?,?> config, Class<T> type) { - return createEntity(EntitySpec.create(config, type)); - } - - @Override - public <T extends Policy> T createPolicy(PolicySpec<T> spec) { - try { - return policyFactory.createPolicy(spec); - } catch (Throwable e) { - log.warn("Failed to create policy using spec "+spec+" (rethrowing)", e); - throw Exceptions.propagate(e); - } - } - - @Override - public <T extends Enricher> T createEnricher(EnricherSpec<T> spec) { - try { - return policyFactory.createEnricher(spec); - } catch (Throwable e) { - log.warn("Failed to create enricher using spec "+spec+" (rethrowing)", e); - throw Exceptions.propagate(e); - } - } - - @Override - public Collection<Entity> getEntities() { - return ImmutableList.copyOf(entityProxiesById.values()); - } - - @Override - public Collection<String> getEntityIds() { - return ImmutableList.copyOf(entityProxiesById.keySet()); - } - - @Override - public Collection<Entity> getEntitiesInApplication(Application application) { - Predicate<Entity> predicate = EntityPredicates.applicationIdEqualTo(application.getId()); - return ImmutableList.copyOf(Iterables.filter(entityProxiesById.values(), predicate)); - } - - @Override - public Collection<Entity> findEntities(Predicate<? super Entity> filter) { - return ImmutableList.copyOf(Iterables.filter(entityProxiesById.values(), filter)); - } - - @Override - public Collection<Entity> findEntitiesInApplication(Application application, Predicate<? super Entity> filter) { - Predicate<Entity> predicate = Predicates.and(EntityPredicates.applicationIdEqualTo(application.getId()), filter); - return ImmutableList.copyOf(Iterables.filter(entityProxiesById.values(), predicate)); - } - - @Override - public Iterable<Entity> getAllEntitiesInApplication(Application application) { - Predicate<Entity> predicate = EntityPredicates.applicationIdEqualTo(application.getId()); - Iterable<Entity> allentities = Iterables.concat(preRegisteredEntitiesById.values(), preManagedEntitiesById.values(), entityProxiesById.values()); - Iterable<Entity> result = Iterables.filter(allentities, predicate); - return ImmutableSet.copyOf(Iterables.transform(result, new Function<Entity, Entity>() { - @Override public Entity apply(Entity input) { - return Entities.proxy(input); - }})); - } - - @Override - public Entity getEntity(String id) { - return entityProxiesById.get(id); - } - - Collection<Application> getApplications() { - return ImmutableList.copyOf(applications); - } - - @Override - public boolean isManaged(Entity e) { - return (isRunning() && getEntity(e.getId()) != null); - } - - boolean isPreRegistered(Entity e) { - return preRegisteredEntitiesById.containsKey(e.getId()); - } - - void prePreManage(Entity entity) { - if (isPreRegistered(entity)) { - log.warn(""+this+" redundant call to pre-pre-manage entity "+entity+"; skipping", - new Exception("source of duplicate pre-pre-manage of "+entity)); - return; - } - preRegisteredEntitiesById.put(entity.getId(), entity); - } - - @Override - public ManagementTransitionMode getLastManagementTransitionMode(String itemId) { - return entityModesById.get(itemId); - } - - @Override - public void setManagementTransitionMode(Entity item, ManagementTransitionMode mode) { - entityModesById.put(item.getId(), mode); - } - - // TODO synchronization issues here. We guard with isManaged(), but if another thread executing - // concurrently then the managed'ness could be set after our check but before we do - // onManagementStarting etc. However, we can't just synchronize because we're calling alien code - // (the user might override entity.onManagementStarting etc). - // - // TODO We need to do some check about isPreManaged - i.e. is there another thread (or is this a - // re-entrant call) where the entity is not yet full managed (i.e. isManaged==false) but we're in - // the middle of managing it. - // - // TODO Also see LocalLocationManager.manage(Entity), if fixing things here - @Override - public void manage(Entity e) { - if (isManaged(e)) { - log.warn(""+this+" redundant call to start management of entity (and descendants of) "+e+"; skipping", - new Exception("source of duplicate management of "+e)); - return; - } - manageRecursive(e, ManagementTransitionMode.guessing(BrooklynObjectManagementMode.NONEXISTENT, BrooklynObjectManagementMode.MANAGED_PRIMARY)); - } - - @Override - public void manageRebindedRoot(Entity item) { - ManagementTransitionMode mode = getLastManagementTransitionMode(item.getId()); - Preconditions.checkNotNull(mode, "Mode not set for rebinding %s", item); - manageRecursive(item, mode); - } - - protected void checkManagementAllowed(Entity item) { - AccessController.Response access = managementContext.getAccessController().canManageEntity(item); - if (!access.isAllowed()) { - throw new IllegalStateException("Access controller forbids management of "+item+": "+access.getMsg()); - } - } - - /* TODO we sloppily use "recursive" to ensure ordering of parent-first in many places - * (which may not be necessary but seems like a good idea), - * and also to collect many entities when doing a big rebind, - * ensuring all have #manageNonRecursive called before calling #onManagementStarted. - * - * it would be better to have a manageAll(Map<Entity,ManagementTransitionMode> items) - * method which did that in two phases, allowing us to selectively rebind, - * esp when we come to want supporting different modes and different brooklyn nodes. - * - * the impl of manageAll could sort them with parents before children, - * (and manageRecursive could simply populate a map and delegate to manageAll). - * - * manageRebindRoot would then go, and the (few) callers would construct the map. - * - * similarly we might want an unmanageAll(), - * although possibly all unmanagement should be recursive, if we assume an entity's ancestors are always at least proxied - * (and the non-recursive RO path here could maybe be dropped) - */ - - /** Applies management lifecycle callbacks (onManagementStarting, for all beforehand, then onManagementStopped, for all after) */ - protected void manageRecursive(Entity e, final ManagementTransitionMode initialMode) { - checkManagementAllowed(e); - - final List<EntityInternal> allEntities = Lists.newArrayList(); - Predicate<EntityInternal> manageEntity = new Predicate<EntityInternal>() { public boolean apply(EntityInternal it) { - ManagementTransitionMode mode = getLastManagementTransitionMode(it.getId()); - if (mode==null) { - setManagementTransitionMode(it, mode = initialMode); - } - - Boolean isReadOnlyFromEntity = it.getManagementSupport().isReadOnlyRaw(); - if (isReadOnlyFromEntity==null) { - if (mode.isReadOnly()) { - // should have been marked by rebinder - log.warn("Read-only entity "+it+" not marked as such on call to manage; marking and continuing"); - } - it.getManagementSupport().setReadOnly(mode.isReadOnly()); - } else { - if (!isReadOnlyFromEntity.equals(mode.isReadOnly())) { - log.warn("Read-only status at entity "+it+" ("+isReadOnlyFromEntity+") not consistent with management mode "+mode); - } - } - - if (it.getManagementSupport().isDeployed()) { - if (mode.wasNotLoaded()) { - // silently bail out - return false; - } else { - if (mode.wasPrimary() && mode.isPrimary()) { - // active partial rebind; continue - } else if (mode.wasReadOnly() && mode.isReadOnly()) { - // reload in RO mode - } else { - // on initial non-RO rebind, should not have any deployed instances - log.warn("Already deployed "+it+" when managing "+mode+"/"+initialMode+"; ignoring this and all descendants"); - return false; - } - } - } - - // check RO status is consistent - boolean isNowReadOnly = Boolean.TRUE.equals( ((EntityInternal)it).getManagementSupport().isReadOnly() ); - if (mode.isReadOnly()!=isNowReadOnly) { - throw new IllegalStateException("Read-only status mismatch for "+it+": "+mode+" / RO="+isNowReadOnly); - } - - allEntities.add(it); - preManageNonRecursive(it, mode); - it.getManagementSupport().onManagementStarting( new ManagementTransitionInfo(managementContext, mode) ); - return manageNonRecursive(it, mode); - } }; - boolean isRecursive = true; - if (initialMode.wasPrimary() && initialMode.isPrimary()) { - // already managed, so this shouldn't be recursive - // (in ActivePartialRebind we cheat, calling in to this method then skipping recursion). - // it also falls through to here when doing a redundant promotion, - // in that case we *should* be recursive; determine by checking whether a child exists and is preregistered. - // the TODO above removing manageRebindRoot in favour of explicit mgmt list would clean this up a lot! - Entity aChild = Iterables.getFirst(e.getChildren(), null); - if (aChild!=null && isPreRegistered(aChild)) { - log.debug("Managing "+e+" in mode "+initialMode+", doing this recursively because a child is preregistered"); - } else { - log.debug("Managing "+e+" but skipping recursion, as mode is "+initialMode); - isRecursive = false; - } - } - if (!isRecursive) { - manageEntity.apply( (EntityInternal)e ); - } else { - recursively(e, manageEntity); - } - - for (EntityInternal it : allEntities) { - if (!it.getManagementSupport().isFullyManaged()) { - ManagementTransitionMode mode = getLastManagementTransitionMode(it.getId()); - ManagementTransitionInfo info = new ManagementTransitionInfo(managementContext, mode); - - it.getManagementSupport().onManagementStarted(info); - managementContext.getRebindManager().getChangeListener().onManaged(it); - } - } - } - - @Override - public void unmanage(final Entity e) { - // TODO don't want to guess; should we inspect state of e ? or maybe it doesn't matter ? - unmanage(e, ManagementTransitionMode.guessing(BrooklynObjectManagementMode.MANAGED_PRIMARY, BrooklynObjectManagementMode.NONEXISTENT)); - } - - public void unmanage(final Entity e, final ManagementTransitionMode mode) { - unmanage(e, mode, false); - } - - private void unmanage(final Entity e, ManagementTransitionMode mode, boolean hasBeenReplaced) { - if (shouldSkipUnmanagement(e)) return; - final ManagementTransitionInfo info = new ManagementTransitionInfo(managementContext, mode); - - 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); - stopTasks(e); - ((EntityInternal)e).getManagementSupport().onManagementStopped(info); - } - // 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); - unmanageNonRecursive(e); - stopTasks(e); - ((EntityInternal)e).getManagementSupport().onManagementStopped(info); - 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 List<EntityInternal> allEntities = Lists.newArrayList(); - recursively(e, new Predicate<EntityInternal>() { public boolean apply(EntityInternal it) { - if (shouldSkipUnmanagement(it)) return false; - allEntities.add(it); - it.getManagementSupport().onManagementStopping(info); - return true; - } }); - - for (EntityInternal it : allEntities) { - if (shouldSkipUnmanagement(it)) continue; - unmanageNonRecursive(it); - stopTasks(it); - } - for (EntityInternal it : allEntities) { - it.getManagementSupport().onManagementStopped(info); - managementContext.getRebindManager().getChangeListener().onUnmanaged(it); - if (managementContext.getGarbageCollector() != null) managementContext.getGarbageCollector().onUnmanaged(e); - } - - } 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()); - } - - private void stopTasks(Entity entity) { - stopTasks(entity, null); - } - - /** stops all tasks (apart from any current one or its descendants) on this entity, - * optionally -- if a timeout is given -- waiting for completion and warning on incomplete tasks */ - @Beta - public void stopTasks(Entity entity, @Nullable Duration timeout) { - CountdownTimer timeleft = timeout==null ? null : timeout.countdownTimer(); - // try forcibly interrupting tasks on managed entities - Collection<Exception> exceptions = MutableSet.of(); - try { - Set<Task<?>> tasksCancelled = MutableSet.of(); - for (Task<?> t: managementContext.getExecutionContext(entity).getTasks()) { - if (entity.equals(BrooklynTaskTags.getContextEntity(Tasks.current())) && hasTaskAsAncestor(t, Tasks.current())) { - // don't cancel if we are running inside a task on the target entity and - // the task being considered is one we have submitted -- e.g. on "stop" don't cancel ourselves! - // but if our current task is from another entity we probably do want to cancel them (we are probably invoking unmanage) - continue; - } - - if (!t.isDone()) { - try { - log.debug("Cancelling "+t+" on "+entity); - tasksCancelled.add(t); - t.cancel(true); - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - log.debug("Error cancelling "+t+" on "+entity+" (will warn when all tasks are cancelled): "+e, e); - exceptions.add(e); - } - } - } - - if (timeleft!=null) { - Set<Task<?>> tasksIncomplete = MutableSet.of(); - // go through all tasks, not just cancelled ones, in case there are previously cancelled ones which are not complete - for (Task<?> t: managementContext.getExecutionContext(entity).getTasks()) { - if (hasTaskAsAncestor(t, Tasks.current())) - continue; - if (!Tasks.blockUntilInternalTasksEnded(t, timeleft.getDurationRemaining())) { - tasksIncomplete.add(t); - } - } - if (!tasksIncomplete.isEmpty()) { - log.warn("Incomplete tasks when stopping "+entity+": "+tasksIncomplete); - } - if (log.isTraceEnabled()) - log.trace("Cancelled "+tasksCancelled+" tasks for "+entity+", with "+ - timeleft.getDurationRemaining()+" remaining (of "+timeout+"): "+tasksCancelled); - } else { - if (log.isTraceEnabled()) - log.trace("Cancelled "+tasksCancelled+" tasks for "+entity+": "+tasksCancelled); - } - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - log.warn("Error inspecting tasks to cancel on unmanagement: "+e, e); - } - if (!exceptions.isEmpty()) - log.warn("Error when cancelling tasks for "+entity+" on unmanagement: "+Exceptions.create(exceptions)); - } - - private boolean hasTaskAsAncestor(Task<?> t, Task<?> potentialAncestor) { - if (t==null || potentialAncestor==null) return false; - if (t.equals(potentialAncestor)) return true; - return hasTaskAsAncestor(t.getSubmittedByTask(), potentialAncestor); - } - - /** - * activates management when effector invoked, warning unless context is acceptable - * (currently only acceptable context is "start") - */ - void manageIfNecessary(Entity entity, Object context) { - if (!isRunning()) { - return; // TODO Still a race for terminate being called, and then isManaged below returning false - } else if (((EntityInternal)entity).getManagementSupport().wasDeployed()) { - return; - } else if (isManaged(entity)) { - return; - } else if (isPreManaged(entity)) { - return; - } else if (Boolean.TRUE.equals(((EntityInternal)entity).getManagementSupport().isReadOnly())) { - return; - } else { - Entity rootUnmanaged = entity; - while (true) { - Entity candidateUnmanagedParent = rootUnmanaged.getParent(); - if (candidateUnmanagedParent == null || isManaged(candidateUnmanagedParent) || isPreManaged(candidateUnmanagedParent)) - break; - rootUnmanaged = candidateUnmanagedParent; - } - if (context == Startable.START.getName()) - log.info("Activating local management for {} on start", rootUnmanaged); - else - log.warn("Activating local management for {} due to effector invocation on {}: {}", new Object[]{rootUnmanaged, entity, context}); - manage(rootUnmanaged); - } - } - - private void recursively(Entity e, Predicate<EntityInternal> action) { - Entity otherPreregistered = preRegisteredEntitiesById.get(e.getId()); - if (otherPreregistered!=null) { - // if something has been pre-registered, prefer it - // (e.g. if we recursing through children, we might have a proxy from previous iteration; - // the most recent will have been pre-registered) - e = otherPreregistered; - } - - boolean success = action.apply( (EntityInternal)e ); - if (!success) { - return; // Don't manage children if action false/unnecessary for parent - } - for (Entity child : e.getChildren()) { - recursively(child, action); - } - } - - /** - * Whether the entity is in the process of being managed. - */ - private synchronized boolean isPreManaged(Entity e) { - return preManagedEntitiesById.containsKey(e.getId()); - } - - /** - * Should ensure that the entity is now known about, but should not be accessible from other entities yet. - * - * Records that the given entity is about to be managed (used for answering {@link #isPreManaged(Entity)}. - * Note that refs to the given entity are stored in a a weak hashmap so if the subsequent management - * attempt fails then this reference to the entity will eventually be discarded (if no-one else holds - * a reference). - */ - private synchronized boolean preManageNonRecursive(Entity e, ManagementTransitionMode mode) { - Entity realE = toRealEntity(e); - - Object old = preManagedEntitiesById.put(e.getId(), realE); - preRegisteredEntitiesById.remove(e.getId()); - - if (old!=null && mode.wasNotLoaded()) { - if (old.equals(e)) { - log.warn("{} redundant call to pre-start management of entity {}, mode {}; ignoring", new Object[] { this, e, mode }); - } else { - throw new IllegalStateException("call to pre-manage entity "+e+" ("+mode+") but different entity "+old+" already known under that id at "+this); - } - return false; - } else { - if (log.isTraceEnabled()) log.trace("{} pre-start management of entity {}, mode {}", - new Object[] { this, e, mode }); - return true; - } - } - - /** - * Should ensure that the entity is now managed somewhere, and known about in all the lists. - * Returns true if the entity has now become managed; false if it was already managed (anything else throws exception) - */ - private synchronized boolean manageNonRecursive(Entity e, ManagementTransitionMode mode) { - Entity old = entitiesById.get(e.getId()); - - if (old!=null && mode.wasNotLoaded()) { - if (old.equals(e)) { - log.warn("{} redundant call to start management of entity {}; ignoring", this, e); - } else { - throw new IllegalStateException("call to manage entity "+e+" ("+mode+") but different entity "+old+" already known under that id at "+this); - } - return false; - } - - BrooklynLogging.log(log, BrooklynLogging.levelDebugOrTraceIfReadOnly(e), - "{} starting management of entity {}", this, e); - Entity realE = toRealEntity(e); - - Entity oldProxy = entityProxiesById.get(e.getId()); - Entity proxyE; - if (oldProxy!=null) { - if (mode.wasNotLoaded()) { - throw new IllegalStateException("call to manage entity "+e+" from unloaded state ("+mode+") but already had proxy "+oldProxy+" already known under that id at "+this); - } - // make the old proxy point at this new delegate - // (some other tricks done in the call below) - ((EntityProxyImpl)(Proxy.getInvocationHandler(oldProxy))).resetDelegate(oldProxy, oldProxy, realE); - proxyE = oldProxy; - } else { - proxyE = toProxyEntityIfAvailable(e); - } - entityProxiesById.put(e.getId(), proxyE); - entityTypes.put(e.getId(), realE.getClass().getName()); - entitiesById.put(e.getId(), realE); - - preManagedEntitiesById.remove(e.getId()); - if ((e instanceof Application) && (e.getParent()==null)) { - applications.add((Application)proxyE); - applicationIds.add(e.getId()); - } - if (!entities.contains(proxyE)) - entities.add(proxyE); - - if (old!=null && old!=e) { - // passing the transition info will ensure the right shutdown steps invoked for old instance - unmanage(old, mode, true); - } - - return true; - } - - /** - * Should ensure that the entity is no longer managed anywhere, remove from all lists. - * Returns true if the entity has been removed from management; if it was not previously managed (anything else throws exception) - */ - private boolean unmanageNonRecursive(Entity e) { - /* - * When method is synchronized, hit deadlock: - * 1. thread called unmanage() on a member of a group, so we got the lock and called group.removeMember; - * this ties to synchronize on AbstractGroupImpl.members - * 2. another thread was doing AbstractGroupImpl.addMember, which is synchronized on AbstractGroupImpl.members; - * it tries to call Entities.manage(child) which calls LocalEntityManager.getEntity(), which is - * synchronized on this. - * - * We MUST NOT call alien code from within the management framework while holding locks. - * The AbstractGroup.removeMember is effectively alien because a user could override it, and because - * it is entity specific. - * - * TODO Does getting then removing from groups risk this entity being added to other groups while - * this is happening? Should abstractEntity.onManagementStopped or some such remove the entity - * from its groups? - */ - - if (!getLastManagementTransitionMode(e.getId()).isReadOnly()) { - e.clearParent(); - for (Group group : e.groups()) { - if (!Entities.isNoLongerManaged(group)) group.removeMember(e); - } - if (e instanceof Group) { - Collection<Entity> members = ((Group)e).getMembers(); - for (Entity member : members) { - if (!Entities.isNoLongerManaged(member)) member.removeGroup((Group)e); - } - } - } else { - log.debug("No relations being updated on unmanage of read only {}", e); - } - - synchronized (this) { - Entity proxyE = toProxyEntityIfAvailable(e); - if (e instanceof Application) { - applications.remove(proxyE); - applicationIds.remove(e.getId()); - } - - entities.remove(proxyE); - entityProxiesById.remove(e.getId()); - entityModesById.remove(e.getId()); - Object old = entitiesById.remove(e.getId()); - - entityTypes.remove(e.getId()); - if (old==null) { - log.warn("{} call to stop management of unknown entity (already unmanaged?) {}; ignoring", this, e); - return false; - } else if (!old.equals(e)) { - // shouldn't happen... - log.error("{} call to stop management of entity {} removed different entity {}", new Object[] { this, e, old }); - return true; - } else { - if (log.isDebugEnabled()) log.debug("{} stopped management of entity {}", this, e); - return true; - } - } - } - - void addEntitySetListener(CollectionChangeListener<Entity> listener) { - //must notify listener in a different thread to avoid deadlock (issue #378) - AsyncCollectionChangeAdapter<Entity> wrappedListener = new AsyncCollectionChangeAdapter<Entity>(managementContext.getExecutionManager(), listener); - entities.addPropertyChangeListener(new GroovyObservablesPropertyChangeToCollectionChangeAdapter(wrappedListener)); - } - - void removeEntitySetListener(CollectionChangeListener<Entity> listener) { - AsyncCollectionChangeAdapter<Entity> wrappedListener = new AsyncCollectionChangeAdapter<Entity>(managementContext.getExecutionManager(), listener); - entities.removePropertyChangeListener(new GroovyObservablesPropertyChangeToCollectionChangeAdapter(wrappedListener)); - } - - private boolean shouldSkipUnmanagement(Entity e) { - if (e==null) { - log.warn(""+this+" call to unmanage null entity; skipping", - new IllegalStateException("source of null unmanagement call to "+this)); - return true; - } - if (!isManaged(e)) { - log.warn("{} call to stop management of unknown entity (already unmanaged?) {}; skipping, and all descendants", this, e); - return true; - } - return false; - } - - private Entity toProxyEntityIfAvailable(Entity e) { - checkNotNull(e, "entity"); - - if (e instanceof EntityProxy) { - return e; - } else if (e instanceof AbstractEntity) { - Entity result = ((AbstractEntity)e).getProxy(); - return (result == null) ? e : result; - } else { - // If we don't already know about the proxy, then use the real thing; presumably it's - // the legacy way of creating the entity so didn't get a preManage() call - - return e; - } - } - - private Entity toRealEntity(Entity e) { - checkNotNull(e, "entity"); - - if (e instanceof AbstractEntity) { - return e; - } else { - Entity result = toRealEntityOrNull(e.getId()); - if (result == null) { - throw new IllegalStateException("No concrete entity known for entity "+e+" ("+e.getId()+", "+e.getEntityType().getName()+")"); - } - return result; - } - } - - public boolean isKnownEntityId(String id) { - return entitiesById.containsKey(id) || preManagedEntitiesById.containsKey(id) || preRegisteredEntitiesById.containsKey(id); - } - - private Entity toRealEntityOrNull(String id) { - Entity result; - // prefer the preRegistered and preManaged entities, during hot proxying, they should be newer - result = preRegisteredEntitiesById.get(id); - if (result==null) - result = preManagedEntitiesById.get(id); - if (result==null) - entitiesById.get(id); - return result; - } - - private boolean isRunning() { - return managementContext.isRunning(); - } - -}
