/* * 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.registry; import static org.mule.runtime.api.i18n.I18nMessageFactory.createStaticMessage; import org.mule.runtime.api.exception.MuleRuntimeException; import org.mule.runtime.api.lifecycle.Disposable; import org.mule.runtime.api.lifecycle.Initialisable; import org.mule.runtime.api.lifecycle.InitialisationException; import org.mule.runtime.api.lifecycle.LifecycleException; import org.mule.runtime.api.lifecycle.Stoppable; import org.mule.runtime.core.api.MuleContext; import org.mule.runtime.core.api.registry.RegistrationException; import org.mule.runtime.core.api.registry.Registry; import org.mule.runtime.core.config.i18n.CoreMessages; import org.mule.runtime.core.lifecycle.RegistryLifecycleManager; import org.mule.runtime.core.util.UUID; import java.util.Collection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AbstractRegistry implements Registry { /** * the unique id for this Registry */ private String id; protected transient Logger logger = LoggerFactory.getLogger(getClass()); protected MuleContext muleContext; protected RegistryLifecycleManager lifecycleManager; protected AbstractRegistry(String id, MuleContext muleContext) { if (id == null) { throw new MuleRuntimeException(CoreMessages.objectIsNull("RegistryID")); } this.id = id; this.muleContext = muleContext; lifecycleManager = createLifecycleManager(); } @Override public final synchronized void dispose() { if (lifecycleManager.getState().isStarted()) { try { getLifecycleManager().fireLifecycle(Stoppable.PHASE_NAME); } catch (LifecycleException e) { logger.error("Failed to shut down registry cleanly: " + getRegistryId(), e); } } // Fire dispose lifecycle before calling doDispose() that that registries can clear any object caches once all objects // are disposed try { getLifecycleManager().fireLifecycle(Disposable.PHASE_NAME); } catch (LifecycleException e) { logger.error("Failed to shut down registry cleanly: " + getRegistryId(), e); } try { doDispose(); } catch (Exception e) { logger.error("Failed to cleanly dispose: " + e.getMessage(), e); } } protected RegistryLifecycleManager createLifecycleManager() { return new RegistryLifecycleManager(getRegistryId(), this, muleContext); } abstract protected void doInitialise() throws InitialisationException; abstract protected void doDispose(); @Override public final void initialise() throws InitialisationException { if (id == null) { logger.warn("No unique id has been set on this registry"); id = UUID.getUUID(); } try { doInitialise(); } catch (InitialisationException e) { throw e; } catch (Exception e) { throw new InitialisationException(e, this); } try { fireLifecycle(Initialisable.PHASE_NAME); } catch (InitialisationException e) { throw e; } catch (LifecycleException e) { if (e.getComponent() instanceof Initialisable) { throw new InitialisationException(e, (Initialisable) e.getComponent()); } throw new InitialisationException(e, this); } } protected boolean isInitialised() { return getLifecycleManager().getState().isInitialised(); } public RegistryLifecycleManager getLifecycleManager() { return lifecycleManager; } @Override public void fireLifecycle(String phase) throws LifecycleException { // Implicitly call stop if necessary when disposing if (Disposable.PHASE_NAME.equals(phase) && lifecycleManager.getState().isStarted()) { getLifecycleManager().fireLifecycle(Stoppable.PHASE_NAME); } getLifecycleManager().fireLifecycle(phase); } @Override @SuppressWarnings("unchecked") public <T> T get(String key) { return (T) lookupObject(key); // do not remove this cast, the CI server fails to compile the code without it } @Override public final Object unregisterObject(String key) throws RegistrationException { Object object = doUnregisterObject(key); try { getLifecycleManager().applyPhase(object, getLifecycleManager().getCurrentPhase(), Disposable.PHASE_NAME); } catch (Exception e) { if (logger.isWarnEnabled()) { logger.warn(String.format("Could not apply shutdown lifecycle to object '%s' after being unregistered.", key), e); } } return object; } /** * {@inheritDoc} */ @Override @Deprecated public final Object unregisterObject(String key, Object metadata) throws RegistrationException { return unregisterObject(key); } /** * Template method for the logic to actually unregister the key without applying any lifecycle to it. Applying the shutdown * lifecycle will be up to {@link #unregisterObject(String)} * * @param key the key of the object to be unregistered object * @return the object which was registered under {@code key} * @throws RegistrationException */ protected abstract Object doUnregisterObject(String key) throws RegistrationException; @Override public <T> T lookupObject(Class<T> type) throws RegistrationException { // Accumulate objects from all registries. Collection<T> objects = lookupObjects(type); if (objects.size() == 1) { return objects.iterator().next(); } else if (objects.size() > 1) { throw new RegistrationException(createStaticMessage("More than one object of type %s registered but only one expected. Objects found are: %s", type, objects.toString())); } else { return null; } } @Override public <T> Collection<T> lookupObjectsForLifecycle(Class<T> type) { // By default use the normal lookup. If a registry implementation needs a // different lookup implementation for lifecycle it should override this // method return lookupObjects(type); } // ///////////////////////////////////////////////////////////////////////// // Registry Metadata // ///////////////////////////////////////////////////////////////////////// @Override public final String getRegistryId() { return id; } }