/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.core.lifecycle; import static java.lang.String.format; import static java.util.Optional.empty; import static java.util.Optional.of; import org.mule.runtime.api.exception.MuleException; import org.mule.runtime.api.lifecycle.Disposable; import org.mule.runtime.api.lifecycle.LifecycleException; import org.mule.runtime.api.lifecycle.Stoppable; import org.mule.runtime.core.api.lifecycle.HasLifecycleInterceptor; import org.mule.runtime.core.api.lifecycle.LifecycleCallback; import org.mule.runtime.core.api.lifecycle.LifecycleInterceptor; import org.mule.runtime.core.api.lifecycle.LifecyclePhase; import org.mule.runtime.core.api.registry.Registry; import org.mule.runtime.core.internal.lifecycle.phases.ContainerManagedLifecyclePhase; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.apache.commons.collections.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An implementation of {@link LifecycleCallback} for applying {@link Registry} lifecycles * * @since 3.7.0 */ public class RegistryLifecycleCallback<T> implements LifecycleCallback<T>, HasLifecycleInterceptor { private static final Logger LOGGER = LoggerFactory.getLogger(RegistryLifecycleCallback.class); protected final RegistryLifecycleManager registryLifecycleManager; private LifecycleInterceptor interceptor = new NullLifecycleInterceptor(); public RegistryLifecycleCallback(RegistryLifecycleManager registryLifecycleManager) { this.registryLifecycleManager = registryLifecycleManager; } @Override public void onTransition(String phaseName, T object) throws MuleException { LifecyclePhase phase = registryLifecycleManager.phases.get(phaseName); if (LOGGER.isDebugEnabled()) { LOGGER.debug(format("Applying lifecycle phase: %s for registry: %s", phase, object.getClass().getSimpleName())); } if (phase instanceof ContainerManagedLifecyclePhase) { phase.applyLifecycle(object); return; } // overlapping interfaces can cause duplicates // TODO: each LifecycleManager should keep this set per executing phase // and clear it when the phase is fully applied Set<Object> duplicates = new HashSet<>(); for (LifecycleObject lifecycleObject : phase.getOrderedLifecycleObjects()) { lifecycleObject.firePreNotification(registryLifecycleManager.muleContext); // TODO Collection -> List API refactoring Collection<?> targetsObj = lookupObjectsForLifecycle(lifecycleObject); doApplyLifecycle(phase, duplicates, lifecycleObject, targetsObj); lifecycleObject.firePostNotification(registryLifecycleManager.muleContext); } interceptor.onPhaseCompleted(phase); } private void doApplyLifecycle(LifecyclePhase phase, Set<Object> duplicates, LifecycleObject lifecycleObject, Collection<?> targetObjects) throws LifecycleException { if (CollectionUtils.isEmpty(targetObjects)) { return; } for (Object target : targetObjects) { if (duplicates.contains(target) || target == null) { continue; } if (LOGGER.isDebugEnabled()) { LOGGER.debug("lifecycle phase: " + phase.getName() + " for object: " + target); } try { if (interceptor.beforePhaseExecution(phase, target)) { phase.applyLifecycle(target); duplicates.add(target); interceptor.afterPhaseExecution(phase, target, empty()); } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug(format( "Skipping the application of the '%s' lifecycle phase over a certain object " + "because a %s interceptor of type [%s] indicated so. Object is: %s", phase.getName(), LifecycleInterceptor.class.getSimpleName(), interceptor.getClass().getName(), target)); } } } catch (Exception e) { interceptor.afterPhaseExecution(phase, target, of(e)); if (phase.equals(Disposable.PHASE_NAME) || phase.equals(Stoppable.PHASE_NAME)) { LOGGER.info(format("Failure executing phase %s over object %s, error message is: %s", phase, target), e.getMessage()); if (LOGGER.isDebugEnabled()) { LOGGER.debug(e.getMessage(), e); } } else { throw e; } } } // the target object might have created and registered a new object // (e.g.: an endpoint which registers a connector) // check if there're new objects for the phase int originalTargetCount = targetObjects.size(); targetObjects = lookupObjectsForLifecycle(lifecycleObject); if (targetObjects.size() > originalTargetCount) { doApplyLifecycle(phase, duplicates, lifecycleObject, targetObjects); } } protected Collection<?> lookupObjectsForLifecycle(LifecycleObject lo) { return registryLifecycleManager.getLifecycleObject().lookupObjectsForLifecycle(lo.getType()); } @Override public void setLifecycleInterceptor(LifecycleInterceptor interceptor) { this.interceptor = interceptor; } }