/* * 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.rebind; import static com.google.common.base.Preconditions.checkNotNull; import java.util.Collections; import java.util.Map; import org.apache.brooklyn.api.effector.Effector; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntityLocal; import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.api.mgmt.rebind.RebindContext; import org.apache.brooklyn.api.mgmt.rebind.mementos.EntityMemento; import org.apache.brooklyn.api.objs.BrooklynObjectType; import org.apache.brooklyn.api.sensor.AttributeSensor; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.enricher.AbstractEnricher; import org.apache.brooklyn.core.entity.AbstractEntity; import org.apache.brooklyn.core.entity.EntityInternal; import org.apache.brooklyn.core.feed.AbstractFeed; import org.apache.brooklyn.core.mgmt.rebind.dto.MementosGenerators; import org.apache.brooklyn.core.policy.AbstractPolicy; import org.apache.brooklyn.entity.group.AbstractGroupImpl; import org.apache.brooklyn.util.exceptions.Exceptions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableList; public class BasicEntityRebindSupport extends AbstractBrooklynObjectRebindSupport<EntityMemento> { private static final Logger LOG = LoggerFactory.getLogger(BasicEntityRebindSupport.class); private final EntityLocal entity; public BasicEntityRebindSupport(AbstractEntity entity) { super(entity); this.entity = checkNotNull(entity, "entity"); } // Can rely on super-type once the deprecated getMementoWithProperties is deleted @Override public EntityMemento getMemento() { return getMementoWithProperties(Collections.<String,Object>emptyMap()); } /** * @deprecated since 0.7.0; use generic config/attributes rather than "custom fields", so use {@link #getMemento()} */ @Deprecated protected EntityMemento getMementoWithProperties(Map<String,?> props) { EntityMemento memento = MementosGenerators.newEntityMementoBuilder(entity).customFields(props).build(); if (LOG.isTraceEnabled()) LOG.trace("Creating memento for entity: {}", memento.toVerboseString()); return memento; } @Override @SuppressWarnings("unchecked") protected void addCustoms(RebindContext rebindContext, EntityMemento memento) { for (Effector<?> eff: memento.getEffectors()) { ((EntityInternal)entity).getMutableEntityType().addEffector(eff); } for (Map.Entry<AttributeSensor<?>, Object> entry : memento.getAttributes().entrySet()) { try { AttributeSensor<?> key = entry.getKey(); Object value = entry.getValue(); @SuppressWarnings("unused") // just to ensure we can load the declared type? or maybe not needed Class<?> type = (key.getType() != null) ? key.getType() : rebindContext.loadClass(key.getTypeName()); ((EntityInternal)entity).setAttributeWithoutPublishing((AttributeSensor<Object>)key, value); } catch (Exception e) { LOG.warn("Error adding custom sensor "+entry+" when rebinding "+entity+" (rethrowing): "+e); throw Exceptions.propagate(e); } } setParent(rebindContext, memento); addChildren(rebindContext, memento); addMembers(rebindContext, memento); addLocations(rebindContext, memento); } @SuppressWarnings("unchecked") @Override protected void addConfig(RebindContext rebindContext, EntityMemento memento) { ConfigKey<?> key = null; for (Map.Entry<ConfigKey<?>, Object> entry : memento.getConfig().entrySet()) { try { key = entry.getKey(); Object value = entry.getValue(); @SuppressWarnings("unused") // just to ensure we can load the declared type? or maybe not needed // In what cases key.getType() will be null? Class<?> type = (key.getType() != null) ? key.getType() : rebindContext.loadClass(key.getTypeName()); entity.config().set((ConfigKey<Object>)key, value); } catch (ClassNotFoundException|IllegalArgumentException e) { rebindContext.getExceptionHandler().onAddConfigFailed(memento, key, e); } } ((EntityInternal)entity).getConfigMap().addToLocalBag(memento.getConfigUnmatched()); ((EntityInternal)entity).refreshInheritedConfig(); } @Override public void addPolicies(RebindContext rebindContext, EntityMemento memento) { for (String policyId : memento.getPolicies()) { AbstractPolicy policy = (AbstractPolicy) rebindContext.lookup().lookupPolicy(policyId); if (policy != null) { try { entity.policies().add(policy); } catch (Exception e) { rebindContext.getExceptionHandler().onAddPolicyFailed(entity, policy, e); } } else { LOG.warn("Policy not found; discarding policy {} of entity {}({})", new Object[] {policyId, memento.getType(), memento.getId()}); rebindContext.getExceptionHandler().onDanglingPolicyRef(policyId); } } } @Override public void addEnrichers(RebindContext rebindContext, EntityMemento memento) { for (String enricherId : memento.getEnrichers()) { AbstractEnricher enricher = (AbstractEnricher) rebindContext.lookup().lookupEnricher(enricherId); if (enricher != null) { try { entity.enrichers().add(enricher); } catch (Exception e) { rebindContext.getExceptionHandler().onAddEnricherFailed(entity, enricher, e); } } else { LOG.warn("Enricher not found; discarding enricher {} of entity {}({})", new Object[] {enricherId, memento.getType(), memento.getId()}); } } } @Override public void addFeeds(RebindContext rebindContext, EntityMemento memento) { for (String feedId : memento.getFeeds()) { AbstractFeed feed = (AbstractFeed) rebindContext.lookup().lookupFeed(feedId); if (feed != null) { try { ((EntityInternal)entity).feeds().addFeed(feed); } catch (Exception e) { rebindContext.getExceptionHandler().onAddFeedFailed(entity, feed, e); } try { if (!rebindContext.isReadOnly(feed)) { feed.start(); } } catch (Exception e) { rebindContext.getExceptionHandler().onRebindFailed(BrooklynObjectType.ENTITY, entity, e); } } else { LOG.warn("Feed not found; discarding feed {} of entity {}({})", new Object[] {feedId, memento.getType(), memento.getId()}); } } } protected void addMembers(RebindContext rebindContext, EntityMemento memento) { if (memento.getMembers().size() > 0) { if (entity instanceof AbstractGroupImpl) { for (String memberId : memento.getMembers()) { Entity member = rebindContext.lookup().lookupEntity(memberId); if (member != null) { ((AbstractGroupImpl)entity).addMemberInternal(member); } else { LOG.warn("Entity not found; discarding member {} of group {}({})", new Object[] {memberId, memento.getType(), memento.getId()}); } } } else { throw new UnsupportedOperationException("Entity with members should be a group: entity="+entity+"; type="+entity.getClass()+"; members="+memento.getMembers()); } } } protected Entity proxy(Entity target) { return target instanceof AbstractEntity ? ((AbstractEntity)target).getProxyIfAvailable() : target; } protected void addChildren(RebindContext rebindContext, EntityMemento memento) { for (String childId : memento.getChildren()) { Entity child = rebindContext.lookup().lookupEntity(childId); if (child != null) { entity.addChild(proxy(child)); } else { LOG.warn("Entity not found; discarding child {} of entity {}({})", new Object[] {childId, memento.getType(), memento.getId()}); } } } protected void setParent(RebindContext rebindContext, EntityMemento memento) { Entity parent = (memento.getParent() != null) ? rebindContext.lookup().lookupEntity(memento.getParent()) : null; if (parent != null) { entity.setParent(proxy(parent)); } else if (memento.getParent() != null){ LOG.warn("Entity not found; discarding parent {} of entity {}({}), so entity will be orphaned and unmanaged", new Object[] {memento.getParent(), memento.getType(), memento.getId()}); } } protected void addLocations(RebindContext rebindContext, EntityMemento memento) { for (String id : memento.getLocations()) { Location loc = rebindContext.lookup().lookupLocation(id); if (loc != null) { ((EntityInternal)entity).addLocations(ImmutableList.of(loc)); } else { LOG.warn("Location not found; discarding location {} of entity {}({})", new Object[] {id, memento.getType(), memento.getId()}); } } } }