com.atlassian.jira.ComponentManager.java Source code

Java tutorial

Introduction

Here is the source code for com.atlassian.jira.ComponentManager.java

Source

package com.atlassian.jira;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.GuardedBy;

import com.atlassian.annotations.Internal;
import com.atlassian.core.util.ClassLoaderUtils;
import com.atlassian.crowd.embedded.api.CrowdService;
import com.atlassian.event.api.EventPublisher;
import com.atlassian.jira.avatar.AvatarManager;
import com.atlassian.jira.bc.filter.SearchRequestAdminService;
import com.atlassian.jira.bc.filter.SearchRequestService;
import com.atlassian.jira.bc.issue.IssueService;
import com.atlassian.jira.bc.issue.search.SearchService;
import com.atlassian.jira.bc.portal.PortalPageService;
import com.atlassian.jira.bc.project.component.ProjectComponentManager;
import com.atlassian.jira.bulkedit.BulkOperationManager;
import com.atlassian.jira.config.ConstantsManager;
import com.atlassian.jira.config.SubTaskManager;
import com.atlassian.jira.config.properties.ApplicationProperties;
import com.atlassian.jira.config.util.AttachmentPathManager;
import com.atlassian.jira.config.util.IndexPathManager;
import com.atlassian.jira.diagnostic.PluginDiagnostics;
import com.atlassian.jira.event.ComponentManagerShutdownEvent;
import com.atlassian.jira.event.ComponentManagerStartedEvent;
import com.atlassian.jira.event.type.EventTypeManager;
import com.atlassian.jira.extension.ContainerProvider;
import com.atlassian.jira.extension.Startable;
import com.atlassian.jira.issue.AttachmentManager;
import com.atlassian.jira.issue.CustomFieldManager;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.IssueFactory;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.RendererManager;
import com.atlassian.jira.issue.changehistory.ChangeHistoryManager;
import com.atlassian.jira.issue.comments.CommentManager;
import com.atlassian.jira.issue.fields.FieldManager;
import com.atlassian.jira.issue.fields.config.manager.IssueTypeSchemeManager;
import com.atlassian.jira.issue.fields.layout.column.ColumnLayoutManager;
import com.atlassian.jira.issue.fields.layout.field.FieldLayoutManager;
import com.atlassian.jira.issue.fields.screen.FieldScreenManager;
import com.atlassian.jira.issue.fields.screen.FieldScreenRendererFactory;
import com.atlassian.jira.issue.fields.screen.FieldScreenSchemeManager;
import com.atlassian.jira.issue.fields.screen.issuetype.IssueTypeScreenSchemeManager;
import com.atlassian.jira.issue.index.IssueIndexManager;
import com.atlassian.jira.issue.link.IssueLinkManager;
import com.atlassian.jira.issue.search.SearchProvider;
import com.atlassian.jira.issue.search.SearchRequestFactory;
import com.atlassian.jira.issue.search.SearchRequestManager;
import com.atlassian.jira.issue.util.IssueUpdater;
import com.atlassian.jira.issue.vote.VoteManager;
import com.atlassian.jira.issue.watchers.WatcherManager;
import com.atlassian.jira.issue.worklog.WorklogManager;
import com.atlassian.jira.mail.MailingListCompiler;
import com.atlassian.jira.mail.SubscriptionMailQueueItemFactory;
import com.atlassian.jira.movesubtask.MoveSubTaskOperationManager;
import com.atlassian.jira.permission.PermissionContextFactory;
import com.atlassian.jira.permission.PermissionTypeManager;
import com.atlassian.jira.permission.SchemePermissions;
import com.atlassian.jira.plugin.ComponentClassManager;
import com.atlassian.jira.plugin.JiraOsgiContainerManager;
import com.atlassian.jira.plugin.assignee.AssigneeResolver;
import com.atlassian.jira.plugin.component.ComponentModuleDescriptor;
import com.atlassian.jira.portal.PortalPageManager;
import com.atlassian.jira.project.ProjectFactory;
import com.atlassian.jira.project.ProjectManager;
import com.atlassian.jira.project.version.VersionManager;
import com.atlassian.jira.security.JiraAuthenticationContext;
import com.atlassian.jira.security.PermissionManager;
import com.atlassian.jira.startup.JiraStartupChecklist;
import com.atlassian.jira.task.TaskManager;
import com.atlassian.jira.template.TemplateManager;
import com.atlassian.jira.upgrade.UpgradeManager;
import com.atlassian.jira.upgrade.UpgradeManagerImpl;
import com.atlassian.jira.user.UserPropertyManager;
import com.atlassian.jira.user.preferences.UserPreferencesManager;
import com.atlassian.jira.user.util.UserUtil;
import com.atlassian.jira.util.JiraDurationUtils;
import com.atlassian.jira.util.Shutdown;
import com.atlassian.jira.util.dbc.Assertions;
import com.atlassian.jira.util.index.IndexLifecycleManager;
import com.atlassian.jira.web.action.admin.translation.TranslationManager;
import com.atlassian.jira.web.action.issue.IssueCreationHelperBean;
import com.atlassian.jira.web.util.FileIconBean;
import com.atlassian.jira.web.util.JiraLocaleUtils;
import com.atlassian.jira.web.util.OutlookDateManager;
import com.atlassian.jira.workflow.WorkflowManager;
import com.atlassian.jira.workflow.WorkflowSchemeManager;
import com.atlassian.mail.server.MailServerManager;
import com.atlassian.plugin.PluginAccessor;
import com.atlassian.plugin.PluginController;
import com.atlassian.plugin.PluginSystemLifecycle;
import com.atlassian.plugin.event.NotificationException;
import com.atlassian.plugin.event.PluginEventManager;
import com.atlassian.plugin.osgi.container.OsgiContainerManager;
import com.atlassian.plugin.webresource.WebResourceManager;
import com.atlassian.security.auth.trustedapps.TrustedApplicationsManager;
import com.atlassian.velocity.VelocityManager;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Sets;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.codehaus.jackson.map.type.TypeBindings;
import org.codehaus.jackson.map.type.TypeFactory;
import org.joda.time.DateTime;
import org.osgi.util.tracker.ServiceTracker;
import org.picocontainer.ComponentAdapter;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.PicoContainer;

import static java.lang.String.format;

/**
 * This component manager uses PicoContainer to resolve all the dependencies between components.
 * <p/>
 * <p/> It is responsible for initialising a large number of components in JIRA. Any components defined here may be
 * injected via a constructor.
 * <p/>
 * <p/> The ComponentManager also has various static accessor methods for non-Pico-managed objects, eg.
 * <code>ComponentManager.getInstance().getProjectManager()</code>. Plugins developers should no longer use these -
 * please use {@link com.atlassian.jira.component.ComponentAccessor} instead.
 * <p/>
 * <p/> More information can be found at the <a href="http://www.picocontainer.org">picocontainer website</a>.
 */
@Internal
public class ComponentManager implements Shutdown {

    public static final String EXTENSION_PROVIDER_PROPERTY = "jira.extension.container.provider";

    private static final Logger log = Logger.getLogger(ComponentManager.class);

    private static final ComponentManager COMPONENT_MANAGER = new ComponentManager();
    private static final String BOOTSTRAP_CONTAINER = "BootstrapContainer";
    private static final String JIRA_CONTAINER = "JIRAContainer";

    //
    // instance fields
    //

    private volatile WrappedComponentContainer container;

    private final PluginSystem pluginSystem = new PluginSystem();

    private volatile ComponentManagerStateImpl state = ComponentManagerStateImpl.NOT_STARTED;

    /**
     * Constructor made private, singleton.
     */
    private ComponentManager() {
    }

    /**
     * Initialization registers components for the bootstrap loading of JIRA.  This gets enough of PICO registered to
     * allow JIRA to bootstrap without a database.
     */
    public void bootstrapInitialise() {
        initComponentContainer(true, BOOTSTRAP_CONTAINER);
        new BootstrapContainerRegistrar().registerComponents(container.getComponentContainer());
        changeState(ComponentManagerStateImpl.CONTAINER_INITIALISED);
    }

    /**
     * If JIRA needs to be setup, then add the extra components needed to the container.
     */
    public void setupInitialise() {
        String error = validateBootstrapContainer();
        if (error != null) {
            throw new IllegalStateException(error);
        }
        new SetupContainerRegistrar().registerComponents(container.getComponentContainer());
    }

    private String validateBootstrapContainer() {
        String errorMessage = null;
        if (container == null) {
            errorMessage = "The bootstrap container has not been initialised, you cannot initialise a Setupcontainer";
        } else if (container.getPicoContainer().getName().startsWith(JIRA_CONTAINER)) {
            errorMessage = "The main JIRA container cannot be used to initialise a SetupContainer";
        } else if (!state.isContainerInitialised()) {
            errorMessage = String.format("The ComponentManager is %s so you cannot initialise a SetupContainer",
                    state.name());
        }
        return errorMessage;
    }

    @VisibleForTesting
    void initialise(final boolean useEagerInitialization) {
        registerComponents(useEagerInitialization);
        registerExtensions();
        runInitializingComponents();
        changeState(ComponentManagerStateImpl.CONTAINER_INITIALISED);
    }

    /**
     * Initialization registers components and then registers extensions.
     */
    public void initialise() {
        initialise(true);
    }

    /**
     * Adds license configuration in license manager.
     */
    public synchronized void start() {
        quickStart();
        // Need to ensure that the components are eagerly instantiated after the "component" plugins had a chance to register.
        // As otherwise the default components are used to instantiate other default components. See JRA-4950
        eagerlyInstantiate();
    }

    /**
     * This is here (outside of the initialise method) as the getComponentInstancesOfType method starts instantiating
     * components and calls on the LicenseComponentAdpater which tries to get reference to this object using the {@link
     * ComponentManager#getInstance()} method. That method returns null as the reference to this object does not exist
     * until the initialise method completes. So this method should be invoked after the initialise method completes
     * execution.
     */
    private void quickStart() {
        // The Jackson TypeFactory singleton caches classes related to the first HashMap and
        // ArrayList that it sees. If this comes from a plugin, it can end up caching classes from
        // OSGi class loaders, which can hang on to memory for far longer than is desirable.  This
        // call forces population of the HashMap cache before the plugin system comes up, and hence
        // before any OSGi class loaders are on the scene. My attempts to safely populate the
        // ArrayList cache have failed - i have never seen it populated in the wild, and the obvious
        // analogue call does not seem to populate the cache, and digging down to call
        // findTypeParameters directly caused crashes in code using jackson.
        TypeFactory.instance.constructType(HashMap.class, (TypeBindings) null);

        getComponent(PluginDiagnostics.class); // eagerly load to catch events on plugin system startup
        pluginSystem.start();

        changeState(ComponentManagerStateImpl.PLUGINSYSTEM_STARTED);
        // now register component plugins before starting anything
        final PluginAccessor pluginAccessor = getPluginAccessor();
        final List<ComponentModuleDescriptor> funNewComponents = pluginAccessor
                .getEnabledModuleDescriptorsByClass(ComponentModuleDescriptor.class);

        if (!funNewComponents.isEmpty()) {
            for (final ComponentModuleDescriptor componentModuleDescriptor : funNewComponents) {
                componentModuleDescriptor.registerComponents(container.getPicoContainer());
            }
        }
        container.getPicoContainer().addComponent(pluginAccessor.getClassLoader());

        changeState(ComponentManagerStateImpl.COMPONENTS_REGISTERED);

        // 1. Call start() if they are startable.
        runStartable();
        // 2. Register components with the EventPublisher if they annotate with @EventComponent.
        registerEventComponents();

        changeState(ComponentManagerStateImpl.STARTED);
        getComponent(EventPublisher.class).publish(ComponentManagerStartedEvent.INSTANCE);
    }

    private void initComponentContainer(boolean useEagerInitialization, String name) {
        if (container != null) {
            throw new IllegalStateException("Component container is already initialized");
        }

        container = new WrappedComponentContainer(new ComponentContainer(useEagerInitialization));
        container.getPicoContainer().setName(name + "_" + DateTime.now().toString());
    }

    private void registerEventComponents() {
        EventPublisher eventPublisher = getComponent(EventPublisher.class);
        Set<Object> registeredListeners = Sets.newIdentityHashSet();
        Collection<ComponentAdapter<?>> componentAdapters = getContainer().getComponentAdapters();
        for (ComponentAdapter<?> componentAdapter : componentAdapters) {
            Class<?> componentKey = componentAdapter.getComponentImplementation();
            if (componentKey.getAnnotation(EventComponent.class) != null) {
                Object instance = componentAdapter.getComponentInstance(container.getPicoContainer(),
                        ComponentAdapter.NOTHING.class);
                if (registeredListeners.add(instance)) {
                    eventPublisher.register(instance);
                }
            }
        }
    }

    private void runInitializingComponents() {
        List<InitializingComponent> components = getContainer().getComponents(InitializingComponent.class);
        for (InitializingComponent component : components) {
            try {
                component.afterInstantiation();
            } catch (final Exception e) {
                log.error("Error occurred while initializing component '" + component.getClass().getName() + "'.",
                        e);
                throw new InfrastructureException(
                        "Error occurred while initializing component '" + component.getClass().getName() + "'.", e);
            }
        }
    }

    private void runStartable() {
        List<Startable> startables = getContainer().getComponents(Startable.class);
        for (Startable startable : startables) {
            try {
                if (!(startable instanceof PluginSystemLifecycle))// don't start the plugin manager twice!
                {
                    startable.start();
                }
            } catch (final Exception e) {
                log.error("Error occurred while starting component '" + startable.getClass().getName() + "'.", e);
                throw new InfrastructureException(
                        "Error occurred while starting component '" + startable.getClass().getName() + "'.", e);
            }
        }

    }

    public synchronized void stop() {
        getComponent(EventPublisher.class).publish(ComponentManagerShutdownEvent.INSTANCE);
        pluginSystem.shutdown();
    }

    public void dispose() {
        //JRADEV-21332:: Ensure the cache descriptors are cleared to release any ClassLoaders they hold
        PropertyUtils.clearDescriptors();
        changeState(ComponentManagerStateImpl.NOT_STARTED);
        //JRADEV-23443 - lets try to free up the permgen before adding the new plugin system
        if (container != null) {
            container.dispose();
            container = null;
        }
        gc();
    }

    public void shutdown() {
        stop();
        dispose();
    }

    private static void gc() {
        int count = 0;
        Object obj = new Object();
        WeakReference<Object> ref = new java.lang.ref.WeakReference<Object>(obj);

        //noinspection UnusedAssignment
        obj = null;

        // break after 100 attempts
        while (count < 10 && ref.get() != null) {
            count++;
            log.debug("Attempting to do a garbage collection:" + count);
            System.gc();
        }
    }

    /**
     * What {@link State} is the {@link ComponentManager} in.
     *
     * @return the current state.
     */
    public State getState() {
        return state;
    }

    /**
     * Eagerly instantiates the container by making a call to {@link org.picocontainer.PicoContainer#getComponents()} ()} method on
     * the container that is returned by {@link ComponentManager#getContainer()} method.
     */
    @GuardedBy("this")
    private void eagerlyInstantiate() {
        // this is to work around synchronisation problems with Pico (PICO-199)
        // http://jira.codehaus.org/browse/PICO-199
        // Pico has problems if it is instantiating A+B from different threads, and both depend on C
        // and they are using synchronised component adapters. You then get a deadlock.
        // This only happens when C is not registered, or C is not registered by its interface,
        // in which case PICO does a full tree walk (from within a synchronised method!).
        // This really needs to get fixed, but one work around is to full instantiate the tree first,
        // in which case, the need for a full tree walk is decreased.
        container.getComponentContainer().initializeEagerComponents();
    }

    private void registerExtensions() {

        final ApplicationProperties applicationProperties = container.getComponentContainer()
                .getComponentInstance(ApplicationProperties.class);
        final String extensionClassName = applicationProperties.getDefaultBackedString(EXTENSION_PROVIDER_PROPERTY);
        try {
            if (!StringUtils.isBlank(extensionClassName)) {
                container.wrapWith(((ContainerProvider) ClassLoaderUtils.loadClass(extensionClassName, getClass())
                        .newInstance()));
            }
        } catch (Exception extensionClassLoadingException) {
            throw new RuntimeException(
                    format("Error loading PICO extension provider container class with name '%s'",
                            extensionClassName),
                    extensionClassLoadingException);
        }
    }

    /**
     * Returns container
     *
     * @return container
     */
    public PicoContainer getContainer() {
        if (container == null) {
            return null;
        }
        return container.getPicoContainer();
    }

    /**
     * Returns container
     *
     * @return container
     */
    public MutablePicoContainer getMutablePicoContainer() {
        final WrappedComponentContainer container = this.container; // volatile read
        return (container != null) ? container.getPicoContainer() : null;
    }

    /**
     * This method registers all components with the internal pico-container.
     * @param useEagerInitialization indicates whether container should initialize all components on startup
     */
    private void registerComponents(final boolean useEagerInitialization) {
        initComponentContainer(useEagerInitialization, JIRA_CONTAINER);
        new ContainerRegistrar().registerComponents(container.getComponentContainer(),
                JiraStartupChecklist.startupOK());
    }

    private ComponentManagerStateImpl changeState(ComponentManagerStateImpl newState) {
        final ComponentManagerStateImpl currentState = state;

        //check whether we want to stop (what we can always do) or step state "by one"
        if (newState != ComponentManagerStateImpl.NOT_STARTED && newState.ordinal() != currentState.ordinal() + 1) {
            throw new IllegalStateException(
                    String.format("Cannot change ComponentManager status from %s to %s", currentState, newState));
        }

        state = newState;
        return currentState;
    }

    /**
     * Retrieves and returns the web resource manager instance
     *
     * @return web resource manager
     */
    public WebResourceManager getWebResourceManager() {
        return getContainer().getComponent(WebResourceManager.class);
    }

    /**
     * Retrieves and returns the attachment manager instance
     *
     * @return attachment manager
     */
    public AttachmentManager getAttachmentManager() {
        return getContainer().getComponent(AttachmentManager.class);
    }

    /**
     * Retrieves and returns the version manager instance
     *
     * @return version manager
     */
    public VersionManager getVersionManager() {
        return getContainer().getComponent(VersionManager.class);
    }

    /**
     * Retrieves and return the bulk operation manager instance
     *
     * @return bulk operation manager
     */
    public BulkOperationManager getBulkOperationManager() {
        return getContainer().getComponent(BulkOperationManager.class);
    }

    /**
     * Retrieves and returns the move subtask operation manager instance
     *
     * @return move subtask operation manager
     */
    public MoveSubTaskOperationManager getMoveSubTaskOperationManager() {
        return getContainer().getComponent(MoveSubTaskOperationManager.class);
    }

    /**
     * Retuns a singleton instance of this class.
     *
     * @return a singleton instance of this class
     *
     * @deprecated Public use of this method is deprecated - please use {@link com.atlassian.jira.component.ComponentAccessor} instead. Since v5.2.
     */
    public static ComponentManager getInstance() {
        return COMPONENT_MANAGER;
    }

    /**
     * Retrieves and returns a component which is an instance of given class.
     * <p>
     * In practise, this is the same as {@link #getComponent(Class)} except it will try to find a unique component that
     * implements/extends the given Class even if the Class is not an actual component key.
     * <p> Please note that this method only gets components from JIRA's core Pico Containter. That is, it retrieves
     * core components and components declared in Plugins1 plugins, but not components declared in Plugins2 plugins.
     * Plugins2 components can be retrieved via the {@link #getOSGiComponentInstanceOfType(Class)} method, but only if
     * they are public.
     *
     * @param clazz class to find a component instance by
     * @return found component
     * @see #getOSGiComponentInstanceOfType(Class)
     * @see PicoContainer#getComponent(Class))
     *
     * @deprecated since 6.0 - please use the jira-api {@link com.atlassian.jira.component.ComponentAccessor#getComponent(Class)} instead
     *
     */
    /*
      NOTE to JIRA DEVS : Stop using this method for general purpose component retrieval.  Use ComponentAccessor please.
    */
    public static <T> T getComponentInstanceOfType(final Class<T> clazz) {
        // Try fast approach
        T component = getComponent(clazz);
        if (component != null) {
            return component;
        }
        // Look the slow way
        component = clazz.cast(getInstance().getContainer().getComponent(clazz));
        if (component != null) {
            // Lets log this so we know there is a naughty component
            if (log.isDebugEnabled()) {
                // Debug mode - include a stacktrace to find the caller
                try {
                    throw new IllegalArgumentException();
                } catch (IllegalArgumentException ex) {
                    log.warn("Unable to find component with key '" + clazz + "' - eventually found '" + component
                            + "' the slow way.", ex);
                }
            } else {
                log.warn("Unable to find component with key '" + clazz + "' - eventually found '" + component
                        + "' the slow way.");
            }
        }
        return component;
    }

    /**
     * Retrieves and returns a component which is an instance of given class.
     * <p>
     * In practise, this is the same as {@link #getComponentInstanceOfType(Class)} except it will fail faster if the
     * given Class is not a known component key (it also has a shorter and more meaningful name).
     * <p>
     * Please note that this method only gets components from JIRA's core Pico Containter. That is, it retrieves
     * core components and components declared in Plugins1 plugins, but not components declared in Plugins2 plugins.
     * Plugins2 components can be retrieved via the {@link #getOSGiComponentInstanceOfType(Class)} method, but only if
     * they are public.
     *
     * @param clazz class to find a component instance by
     * @return found component, or null if not found
     * @see #getOSGiComponentInstanceOfType(Class)
     * @see PicoContainer#getComponent(Object)
     *
     * @deprecated since 6.0 - please use the jira-api {@link com.atlassian.jira.component.ComponentAccessor#getComponent(Class)} instead
     */
    /*
      NOTE to JIRA DEVS : Stop using this method for general purpose component retrieval.  Use ComponentAccessor please.
    */
    public static <T> T getComponent(final Class<T> clazz) {
        return getInstance().getContainer().getComponent(clazz);
    }

    /**
     * Retrieves and returns a public component from OSGi land via its class name.  This method can be used to retrieve
     * a component provided via a plugins2 OSGi bundle.  Please note that components returned via this method should
     * *NEVER* be cached (e.g. in a static field) as they may be refreshed at any time as a plugin is enabled/disabled
     * or the componentManager is reinitialised (after an XML import).
     * <p>
     * Plugin developers should prefer the API method {@link com.atlassian.jira.component.ComponentAccessor#getOSGiComponentInstanceOfType(Class)}.
     * <p> It is important to note that this only works for public components. That is components with {@code
     * public="true"} declared in their XML configuration. This means that they are available for other plugins to
     * import.
     * <p> A use case for this is when for example for the dashboards plugin.  In several areas in JIRA we may want to
     * render gadgets via the {@link com.atlassian.gadgets.view.GadgetViewFactory}.  Whilst the interface for this
     * component is available in JIRA core, the implementation is provided by the dashboards OSGi bundle.  This method
     * will allow us to access it.
     *
     * @param clazz class to find an OSGi component instance for
     * @return found component
     * @see #getComponentInstanceOfType(Class)
     *
     * @deprecated since 6.0 - please use the jira-api {@link com.atlassian.jira.component.ComponentAccessor#getOSGiComponentInstanceOfType(Class)} instead
     */
    /*
      NOTE to JIRA DEVS : Stop using this method for general purpose component retrieval.  Use ComponentAccessor please.
    */
    public static <T> T getOSGiComponentInstanceOfType(final Class<T> clazz) {
        Assertions.notNull("class", clazz);

        OsgiContainerManager osgiContainerManager = getComponentInstanceOfType(OsgiContainerManager.class);
        if (osgiContainerManager != null) {
            // this is the happy path. uses a cached service tracker to get the component
            if (osgiContainerManager instanceof JiraOsgiContainerManager) {
                return ((JiraOsgiContainerManager) osgiContainerManager).getOsgiComponentOfType(clazz);
            }

            // in practice we will never run this code, since we have installed a JiraOsgiContainerManager into Pico.
            // however, let's degrade gracefully if it does happen for some reason. belts and braces-style.
            return getOsgiComponentOfType(clazz, osgiContainerManager);
        }

        return null;
    }

    /**
     * Returns all the components currently inside of Pico which are instances of the given class.
     *
     * @param clazz the class to search for.
     * @return a list containing all the instances of the passed class registered in JIRA's pico container.
     */
    public static <T> List<T> getComponentsOfType(final Class<T> clazz) {
        final PicoContainer pico = getInstance().getContainer();
        final List<ComponentAdapter<T>> adapters = pico.getComponentAdapters(clazz);
        if (adapters.isEmpty()) {
            return Collections.emptyList();
        } else {
            final List<T> returnList = new ArrayList<T>(adapters.size());
            for (final ComponentAdapter<T> adapter : adapters) {
                // remove cast when we go to a Java5 pico
                returnList.add(clazz.cast(adapter.getComponentInstance(pico)));
            }
            return Collections.unmodifiableList(returnList);
        }
    }

    /**
     * Returns all the components currently inside Pico which are instances of the given class, mapping them to their
     * component key.
     *
     * @param iface The class to search for
     * @return a map, mapping the component key, to the instances of the clas registered in JIRA's pico container.
     */
    public static <T> Map<String, T> getComponentsOfTypeMap(final Class<T> iface) {
        final PicoContainer picoContainer = getInstance().getContainer();
        final List<ComponentAdapter<T>> componentAdaptersOfType = picoContainer.getComponentAdapters(iface);

        final Map<String, T> implementations = new HashMap<String, T>();
        for (final ComponentAdapter<T> componentAdapter : componentAdaptersOfType) {
            final T componentInstance = iface.cast(componentAdapter.getComponentInstance(picoContainer));
            implementations.put(String.valueOf(componentAdapter.getComponentKey()), componentInstance);
        }
        return Collections.unmodifiableMap(implementations);
    }

    private static class PluginSystem {
        enum State {
            NOT_STARTED, STARTED
        }

        volatile State state = State.NOT_STARTED;

        /**
         * Retrieves and returns the plugin system's lifecycle instance
         *
         * @return plugin lifecycle
         */
        public PluginSystemLifecycle getPluginSystemLifecycle() {
            return getComponentInstanceOfType(PluginSystemLifecycle.class);
        }

        void start() {
            if (state != State.NOT_STARTED) {
                return;
            }
            // start plugin manager first manually so that the component plugins can be startable themselves.
            final PluginSystemLifecycle pluginSystemLifecycle = getPluginSystemLifecycle();
            if (pluginSystemLifecycle instanceof Startable) {
                final Startable startablePluginManager = (Startable) pluginSystemLifecycle;
                try {
                    startablePluginManager.start();
                } catch (final NotificationException ex) {
                    // This is just a wrapper from the Plugin Events system - lets get the underlying cause.
                    final Throwable cause = ex.getCause();
                    throw new InfrastructureException(
                            "Error occurred while starting Plugin Manager. " + cause.getMessage(), cause);
                } catch (final Exception e) {
                    throw new InfrastructureException(
                            "Error occurred while starting Plugin Manager. " + e.getMessage(), e);
                }
            } else {
                throw new InfrastructureException("PluginManager does not implement startable anymore?!");
            }
            state = State.STARTED;
        }

        public void shutdown() {
            if (state != State.STARTED) {
                return;
            }
            try {
                getPluginSystemLifecycle().shutdown();
            } catch (final RuntimeException ignore) {
                // if the plugin system hasn't been started for some reason or has been closed down it will throw an IllegalState
                // we don't care as long as it gets into the not started state  - it also leaks RuntimeExceptions
                // at least log something to help the developer track this down
                log.error("Error occurred while shutting down the component manager.", ignore);
            }
            state = State.NOT_STARTED;
        }
    }

    /**
     * The state of the {@link ComponentManager}.
     *
     * @since 4.0
     */
    public interface State {
        /**
         * Has the PICO container initialised.
         *
         * @return true if the PICO container is set up
         */
        boolean isContainerInitialised();

        /**
         * Have the components registered been with PICO including plugin components.
         *
         * @return true if the plugin system has started.
         */
        boolean isPluginSystemStarted();

        /**
         * Have the components registered been with PICO including plugin components.
         *
         * @return true if components have been registered.
         */
        boolean isComponentsRegistered();

        /**
         * Has the {@link ComponentManager} started
         *
         * @return true if the component manager has started.
         */
        boolean isStarted();
    }

    /**
     ===============================================================================
     Before we had generics it made sense to have type safe accessors for the various
     components but these days it is a code smell and I think we should deprecate these
     and the {@link ManagerFactory} - BB mar 2011
     ===============================================================================
     */

    /**
     * Retrieves and returns the issue updater instance NOTE: This method is only used for tests. The fact that it
     * exists means that tests need to be rewritten
     *
     * @return issue updater
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public IssueUpdater getIssueUpdater() {
        return getContainer().getComponent(IssueUpdater.class);
    }

    /**
     * Retrieves and returns the Issue Creation Helper Bean instance.
     *
     * @return issue creation helper bean
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public IssueCreationHelperBean getIssueCreationHelperBean() {
        return getContainer().getComponent(IssueCreationHelperBean.class);
    }

    /**
     * Retrieves and returns the file icon bean instance
     *
     * @return file icon bean
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public FileIconBean getFileIconBean() {
        return getContainer().getComponent(FileIconBean.class);
    }

    /**
     * Retrieves and returns the issue manager instance
     *
     * @return issue manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public IssueManager getIssueManager() {
        return getComponentInstanceOfType(IssueManager.class);
    }

    /**
     * Retrieves and returns the workflow manager instance
     *
     * @return workflow manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public WorkflowManager getWorkflowManager() {
        return getContainer().getComponent(WorkflowManager.class);
    }

    /**
     * Retrieves and returns the worklog manager instance
     *
     * @return worklog manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public WorklogManager getWorklogManager() {
        return getContainer().getComponent(WorklogManager.class);
    }

    /**
     * Get an IssueFactory instance, particularly useful for obtaining {@link Issue} from
     *
     * @return IssueFactory
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    @SuppressWarnings({ "JavadocReference" })
    public IssueFactory getIssueFactory() {
        return getContainer().getComponent(IssueFactory.class);
    }

    /**
     * Retrieves and returns the project factory instance
     *
     * @return project factory
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public ProjectFactory getProjectFactory() {
        return getContainer().getComponent(ProjectFactory.class);
    }

    /**
     * Retrieves and returns the constants manager
     *
     * @return constants manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public ConstantsManager getConstantsManager() {
        return getContainer().getComponent(ConstantsManager.class);
    }

    /**
     * Retrieves and returns the field manager instance
     *
     * @return field manager
     *
     * @deprecated Use {@link com.atlassian.jira.component.ComponentAccessor#getFieldManager()} instead. Since v4.4.
     */
    public FieldManager getFieldManager() {
        return getContainer().getComponent(FieldManager.class);
    }

    /**
     * Retrieves and returns the custom field manager
     *
     * @return custom field manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public CustomFieldManager getCustomFieldManager() {
        return getContainer().getComponent(CustomFieldManager.class);
    }

    /**
     * Retrieves and returns the issue type scheme manager instance
     *
     * @return issue type scheme manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public IssueTypeSchemeManager getIssueTypeSchemeManager() {
        return getContainer().getComponent(IssueTypeSchemeManager.class);
    }

    /**
     * Retrieves and returns the issue type screen scheme manager instance
     *
     * @return issue type screen scheme manager
     *
     * @deprecated Use {@link com.atlassian.jira.component.ComponentAccessor#getIssueTypeScreenSchemeManager()} instead. Since v5.0.
     */
    public IssueTypeScreenSchemeManager getIssueTypeScreenSchemeManager() {
        return getContainer().getComponent(IssueTypeScreenSchemeManager.class);
    }

    /**
     * Retrieves and returns the subtask manager instance
     *
     * @return subtask manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public SubTaskManager getSubTaskManager() {
        return getContainer().getComponent(SubTaskManager.class);
    }

    /**
     * Retrieves and returns the issuel link manager instance NOTE: Needed especially for custom workflow conditions
     * that check an issue's links for progression.
     *
     * @return issuel link manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public IssueLinkManager getIssueLinkManager() {
        return getContainer().getComponent(IssueLinkManager.class);
    }

    /**
     * Retrieves and returns the application properties.
     *
     * @return application properties
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public ApplicationProperties getApplicationProperties() {
        return getContainer().getComponent(ApplicationProperties.class);
    }

    /**
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public CrowdService getCrowdService() {
        return getContainer().getComponent(CrowdService.class);
    }

    /**
     * Retrieves and returns the permission manager instance
     *
     * @return permission manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public PermissionManager getPermissionManager() {
        return getContainer().getComponent(PermissionManager.class);
    }

    /**
     * Retrieves and returns the permission type manager instance
     *
     * @return permission type manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public PermissionTypeManager getPermissionTypeManager() {
        return getContainer().getComponent(PermissionTypeManager.class);
    }

    /**
     * Retrieves and returns the field layout manager
     *
     * @return field layout manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public FieldLayoutManager getFieldLayoutManager() {
        return getContainer().getComponent(FieldLayoutManager.class);
    }

    /**
     * Retrieves and returns the column layout manager instance
     *
     * @return column layout manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public ColumnLayoutManager getColumnLayoutManager() {
        return getContainer().getComponent(ColumnLayoutManager.class);
    }

    /**
     * Retrieves and returns the project manager instance
     *
     * @return project manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public ProjectManager getProjectManager() {
        return getContainer().getComponent(ProjectManager.class);
    }

    /**
     * Retrieves and returns the vote manager instance
     *
     * @return vote manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public VoteManager getVoteManager() {
        return getContainer().getComponent(VoteManager.class);
    }

    /**
     * Retrieves and returns the JIRA locale utils instance
     *
     * @return JIRA locale utils
     *
     * @deprecated Get LocaleManager/LocaleParser injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public JiraLocaleUtils getJiraLocaleUtils() {
        return getContainer().getComponent(JiraLocaleUtils.class);
    }

    /**
     * Retrieves and returns the plugin system's lifecycle instance
     *
     * @return plugin lifecycle
     */
    public PluginSystemLifecycle getPluginSystemLifecycle() {
        return pluginSystem.getPluginSystemLifecycle();
    }

    /**
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public PluginAccessor getPluginAccessor() {
        return getContainer().getComponent(PluginAccessor.class);
    }

    /**
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public PluginEventManager getPluginEventManager() {
        return getContainer().getComponent(PluginEventManager.class);
    }

    /**
     * Gets the ComponentClassManager component.
     *
     * @return the ComponentClassManager component.
     *
     * @deprecated Use {@link com.atlassian.jira.component.ComponentAccessor#getComponentClassManager()} instead. Since v5.0.
     */
    public ComponentClassManager getComponentClassManager() {
        return getContainer().getComponent(ComponentClassManager.class);
    }

    /**
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public PluginController getPluginController() {
        return getContainer().getComponent(PluginController.class);
    }

    /**
     * Retrieves and returns the upgrade manager instance
     *
     * @return upgrade manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public UpgradeManager getUpgradeManager() {
        return getContainer().getComponent(UpgradeManager.class);
    }

    /**
     * Retrieves and returns the renderer manager instance
     *
     * @return renderer manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public RendererManager getRendererManager() {
        return getContainer().getComponent(RendererManager.class);
    }

    /**
     * Retrieves and returns the field screen renderer factory instance
     *
     * @return field screen renderer factory
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public FieldScreenRendererFactory getFieldScreenRendererFactory() {
        return getContainer().getComponent(FieldScreenRendererFactory.class);
    }

    /**
     * Retrieves and returns the workflow scheme manager instance
     *
     * @return workflow scheme manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public WorkflowSchemeManager getWorkflowSchemeManager() {
        return getContainer().getComponent(WorkflowSchemeManager.class);
    }

    /**
     * Retrieves and returns the index lifecycle manager instance
     *
     * @return index lifecycle manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public IndexLifecycleManager getIndexLifecycleManager() {
        return getContainer().getComponent(IndexLifecycleManager.class);
    }

    /**
     * Retrieves and returns the issue index manager instance
     *
     * @return index manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public IssueIndexManager getIndexManager() {
        return getContainer().getComponent(IssueIndexManager.class);
    }

    /**
     * Retrieves and returns the issue service instance
     *
     * @return issue service
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public IssueService getIssueService() {
        return getComponentInstanceOfType(IssueService.class);
    }

    /**
     * Retrieves and returns the index path manager instance
     *
     * @return index path manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public IndexPathManager getIndexPathManager() {
        return getComponentInstanceOfType(IndexPathManager.class);
    }

    /**
     * Retrieves and returns the attachment path instance
     *
     * @return attachment path manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public AttachmentPathManager getAttachmentPathManager() {
        return getComponentInstanceOfType(AttachmentPathManager.class);
    }

    /**
     * Retrieves and returns the translation manager instance
     *
     * @return translation manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public TranslationManager getTranslationManager() {
        return getContainer().getComponent(TranslationManager.class);
    }

    /**
     * Retrieves and returns the JIRA authentication context instance
     *
     * @return JIRA authentication context
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public JiraAuthenticationContext getJiraAuthenticationContext() {
        return getContainer().getComponent(JiraAuthenticationContext.class);
    }

    /**
     * Retrieves and returns the watcher manager instance
     *
     * @return watcher manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public WatcherManager getWatcherManager() {
        return getContainer().getComponent(WatcherManager.class);
    }

    /**
     * Retrieves and returns the search provider instance
     *
     * @return search provider
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public SearchService getSearchService() {
        return getContainer().getComponent(SearchService.class);
    }

    /**
     * Retrieves and returns the search provider instance
     *
     * @return search provider
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public SearchProvider getSearchProvider() {
        return getContainer().getComponent(SearchProvider.class);
    }

    /**
     * Retrieves and returns the search request manager instance
     *
     * @return search request manager
     * @deprecated v3.13 please use {@link SearchRequestService}
     */
    @Deprecated
    public SearchRequestManager getSearchRequestManager() {
        return getContainer().getComponent(SearchRequestManager.class);
    }

    /**
     * Retrieves the search request service
     *
     * @return search request service
     * @since v3.13
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public SearchRequestService getSearchRequestService() {
        return getContainer().getComponent(SearchRequestService.class);
    }

    /**
     * Retrieves the search request admin service
     *
     * @return search request service
     * @since v3.13
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public SearchRequestAdminService getSearchRequestAdminService() {
        return getContainer().getComponent(SearchRequestAdminService.class);
    }

    /**
     * Retrieves a {@link SearchRequestFactory}
     *
     * @return search request factory
     * @since v3.13
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public SearchRequestFactory getSearchRequestFactory() {
        return getContainer().getComponent(SearchRequestFactory.class);
    }

    /**
     * Retrieves and returns the field screen manager instance
     *
     * @return field screen manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public FieldScreenManager getFieldScreenManager() {
        return getContainer().getComponent(FieldScreenManager.class);
    }

    /**
     * Retrieves and returns the field screen scheme manager instance
     *
     * @return field screen scheme manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public FieldScreenSchemeManager getFieldScreenSchemeManager() {
        return getContainer().getComponent(FieldScreenSchemeManager.class);
    }

    /**
     * Retrieves and returns the scheme permissions instance
     *
     * @return scheme permissions
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public SchemePermissions getSchemePermissions() {
        return getContainer().getComponent(SchemePermissions.class);
    }

    /**
     * Retrieves and returns the mail server manager instance
     *
     * @return mail server manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public MailServerManager getMailServerManager() {
        return getContainer().getComponent(MailServerManager.class);
    }

    /**
     * Retrieves and returns teh event type manager instance
     *
     * @return event type manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public EventTypeManager getEventTypeManager() {
        return getContainer().getComponent(EventTypeManager.class);
    }

    /**
     * Retrieves and returns the template manager instance
     *
     * @return template manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public TemplateManager getTemplateManager() {
        return getContainer().getComponent(TemplateManager.class);
    }

    /**
     * Retrieves and returns the user util instance
     *
     * @return user util
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public UserUtil getUserUtil() {
        return getContainer().getComponent(UserUtil.class);
    }

    /**
     * Retrieves and returns the assignee resolver instance
     *
     * @return assignee resolver
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public AssigneeResolver getAssigneeResolver() {
        return getContainer().getComponent(AssigneeResolver.class);
    }

    /**
     * Retrieves and returns the mailing list compiler instance
     *
     * @return mailing list compiler
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public MailingListCompiler getMailingListCompiler() {
        return getContainer().getComponent(MailingListCompiler.class);
    }

    /**
     * Retrieves and returns the subscription mail queue item factory instance
     *
     * @return subscription mail queue item factory
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public SubscriptionMailQueueItemFactory getSubscriptionMailQueueItemFactory() {
        return getContainer().getComponent(SubscriptionMailQueueItemFactory.class);
    }

    /**
     * Retrieves and returns the velocity manager instance
     *
     * @return velocity manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public VelocityManager getVelocityManager() {
        return getContainer().getComponent(VelocityManager.class);
    }

    /**
     * Retrieves and returns the comment manager instance
     *
     * @return comment manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public CommentManager getCommentManager() {
        return getContainer().getComponent(CommentManager.class);
    }

    /**
     * Create a new UpgradeManager. This may be needed if more upgrade tasks are added, or if the license has been
     * changed.
     */
    public void refreshUpgradeManager() {
        // this is very ugly. We should find a way to get Pico to reload its classes.
        container.getPicoContainer().removeComponent(UpgradeManager.class);
        container.getPicoContainer().addComponent(UpgradeManager.class, UpgradeManagerImpl.class);
    }

    /**
     * Retrieves and returns the project component manager instance
     *
     * @return project component manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public ProjectComponentManager getProjectComponentManager() {
        return getContainer().getComponent(ProjectComponentManager.class);
    }

    /**
     * Retrieves and returns the {@link ChangeHistoryManager} manager instance
     *
     * @return ChangeHistoryManager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public ChangeHistoryManager getChangeHistoryManager() {
        return getContainer().getComponent(ChangeHistoryManager.class);
    }

    /**
     * Retrieves and returns the permission context factory instance
     *
     * @return permission context factory
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public PermissionContextFactory getPermissionContextFactory() {
        return getContainer().getComponent(PermissionContextFactory.class);
    }

    /**
     * Retrieves and returns the user preferences manager instance
     *
     * @return user preferences manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public UserPreferencesManager getUserPreferencesManager() {
        return getContainer().getComponent(UserPreferencesManager.class);
    }

    /**
     * Retrieves and returns the user preferences manager instance
     *
     * @return user preferences manager
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public UserPropertyManager getUserPropertyManager() {
        return getContainer().getComponent(UserPropertyManager.class);
    }

    /**
     * Retrieves and returns the JIRA duration utils instance
     *
     * @return JIRA duration utils
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public JiraDurationUtils getJiraDurationUtils() {
        return getContainer().getComponent(JiraDurationUtils.class);
    }

    /**
     * Returns the {@link com.atlassian.jira.task.TaskManager}
     *
     * @return the {@link com.atlassian.jira.task.TaskManager}
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public TaskManager getTaskManager() {
        return getContainer().getComponent(TaskManager.class);
    }

    /**
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public TrustedApplicationsManager getTrustedApplicationsManager() {
        return getContainer().getComponent(TrustedApplicationsManager.class);
    }

    /**
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public OutlookDateManager getOutlookDateManager() {
        return getContainer().getComponent(OutlookDateManager.class);
    }

    /**
     * @return the {@link com.atlassian.jira.bc.portal.PortalPageService}
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public PortalPageService getPortalPageService() {
        return getContainer().getComponent(PortalPageService.class);
    }

    /**
     * @return the {@link com.atlassian.jira.portal.PortalPageManager}
     *
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public PortalPageManager getPortalPageManager() {
        return getContainer().getComponent(PortalPageManager.class);
    }

    /**
     * @deprecated Get this component injected in your constructor or use {@link com.atlassian.jira.component.ComponentAccessor} for static access instead. Since v5.2.
     */
    public AvatarManager getAvatarManager() {
        return getContainer().getComponent(AvatarManager.class);
    }

    /**
     * Looks up a service from the OsgiContainerManager. This method should be avoided since it creates and closes a
     * new ServiceTracker each time it is called.
     *
     * @see JiraOsgiContainerManager#getOsgiComponentOfType(Class)
     */
    private static <T> T getOsgiComponentOfType(@Nonnull Class<T> clazz,
            @Nonnull OsgiContainerManager osgiContainerManager) {
        if (log.isDebugEnabled()) {
            log.debug(String.format(
                    "Using slow getOsgiComponentOfType() to get '%s'. COMPONENT MANAGER. Y U NO JiraOsgiContainerManager!?",
                    clazz.getName()), new Throwable());
        }

        ServiceTracker serviceTracker = osgiContainerManager.getServiceTracker(clazz.getName());
        if (serviceTracker != null) {
            try {
                return clazz.cast(serviceTracker.getService());
            } finally {
                serviceTracker.close();
            }
        }

        return null;
    }
}