All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.almworks.jira.structure.api.util.JiraComponents Maven / Gradle / Ivy

There is a newer version: 17.25.3
Show newest version
package com.almworks.jira.structure.api.util;

import com.almworks.jira.structure.api.lifecycle.CachingComponent;
import com.atlassian.jira.avatar.AvatarManager;
import com.atlassian.jira.bc.project.component.ProjectComponentManager;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.config.ConstantsManager;
import com.atlassian.jira.config.properties.ApplicationProperties;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.customfields.manager.OptionsManager;
import com.atlassian.jira.plugin.ComponentClassManager;
import com.atlassian.jira.project.ProjectManager;
import com.atlassian.jira.project.version.VersionManager;
import com.atlassian.jira.security.*;
import com.atlassian.jira.security.groups.GroupManager;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.user.util.UserManager;
import com.atlassian.jira.user.util.UserUtil;
import com.atlassian.plugin.PluginAccessor;
import org.jetbrains.annotations.*;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import java.lang.reflect.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class JiraComponents implements DisposableBean, InitializingBean, CachingComponent {
  private static final Map, ? super Object> proxyCache = new ConcurrentHashMap<>();

  @Nullable
  public static  T getOSGiComponentInstanceOfType(@NotNull Class intfClass) {
    assert intfClass.isInterface() : intfClass;
    T service = ComponentAccessor.getOSGiComponentInstanceOfType(intfClass);
    return createTCCLSwitchingProxy(intfClass, service);
  }

  @Nullable
  public static  T getComponentOfType(@NotNull Class intfClass) {
    assert intfClass.isInterface() : intfClass;
    T service = ComponentAccessor.getComponentOfType(intfClass);
    return getTCCLSwitchingProxy(intfClass, service);
  }

  @Nullable
  public static  T getComponent(@NotNull Class intfClass) {
    assert intfClass.isInterface() : intfClass;
    T service = ComponentAccessor.getComponent(intfClass);
    return getTCCLSwitchingProxy(intfClass, service);
  }

  public static JiraAuthenticationContext getJiraAuthenticationContext() {
    return getTCCLSwitchingProxy(JiraAuthenticationContext.class, ComponentAccessor.getJiraAuthenticationContext());
  }

  public static ProjectManager getProjectManager() {
    return getTCCLSwitchingProxy(ProjectManager.class, ComponentAccessor.getProjectManager());
  }

  public static ProjectComponentManager getProjectComponentManager() {
    return getTCCLSwitchingProxy(ProjectComponentManager.class, ComponentAccessor.getProjectComponentManager());
  }

  public static ConstantsManager getConstantsManager() {
    return getTCCLSwitchingProxy(ConstantsManager.class, ComponentAccessor.getConstantsManager());
  }

  public static VersionManager getVersionManager() {
    return getTCCLSwitchingProxy(VersionManager.class, ComponentAccessor.getVersionManager());
  }

  public static OptionsManager getOptionsManager() {
    return getTCCLSwitchingProxy(OptionsManager.class, ComponentAccessor.getOptionsManager());
  }

  public static UserManager getUserManager() {
    return getTCCLSwitchingProxy(UserManager.class, ComponentAccessor.getUserManager());
  }

  public static GroupManager getGroupManager() {
    return getTCCLSwitchingProxy(GroupManager.class, ComponentAccessor.getGroupManager());
  }

  public static UserUtil getUserUtil() {
    return getTCCLSwitchingProxy(UserUtil.class, ComponentAccessor.getUserUtil());
  }

  public static PluginAccessor getPluginAccessor() {
    return getTCCLSwitchingProxy(PluginAccessor.class, ComponentAccessor.getPluginAccessor());
  }

  public static PermissionManager getPermissionManager() {
    return getTCCLSwitchingProxy(PermissionManager.class, ComponentAccessor.getPermissionManager());
  }

  public static ApplicationProperties getApplicationProperties() {
    return getTCCLSwitchingProxy(ApplicationProperties.class, ComponentAccessor.getApplicationProperties());
  }

  public static IssueManager getIssueManager() {
    return getTCCLSwitchingProxy(IssueManager.class, ComponentAccessor.getIssueManager());
  }

  public static AvatarManager getAvatarManager() {
    return getTCCLSwitchingProxy(AvatarManager.class, ComponentAccessor.getAvatarManager());
  }

  public static ComponentClassManager getComponentClassManager() {
    return getTCCLSwitchingProxy(ComponentClassManager.class, ComponentAccessor.getComponentClassManager());
  }

  public static GlobalPermissionManager getGlobalPermissionManager() {
    return getTCCLSwitchingProxy(GlobalPermissionManager.class, ComponentAccessor.getGlobalPermissionManager());
  }

  @Contract("_, null -> null; _, !null -> !null")
  private static  T getTCCLSwitchingProxy(@NotNull Class intfClass, @Nullable T service) {
    if (service == null) return null;
    Object cache = proxyCache.get(intfClass);
    if (cache != null) {
      // noinspection unchecked
      return (T) cache;
    }
    T proxy = createTCCLSwitchingProxy(intfClass, service);
    proxyCache.put(intfClass, proxy);
    return proxy;
  }

  @Contract("_, null -> null; _, !null -> !null")
  private static  T createTCCLSwitchingProxy(@NotNull Class intfClass, @Nullable T service) {
    // noinspection Contract
    assert intfClass.isInterface() : intfClass;
    // noinspection unchecked
    return service == null ? null : (T) Proxy.newProxyInstance(
      service.getClass().getClassLoader(), new Class[] {intfClass},
      new TCCLSwitchingInvocationHandler(service));
  }

  @Override
  public final void afterPropertiesSet() throws Exception {
    proxyCache.clear();
  }

  @Override
  public final void destroy() throws Exception {
    proxyCache.clear();
  }

  @Override
  public void clearCaches() {
    proxyCache.clear();
  }

  @Override
  public void clearUserCaches(@NotNull ApplicationUser user) {
  }

  
  private static final class TCCLSwitchingInvocationHandler implements InvocationHandler {
    private final Object myService;
    private final ClassLoader myClassLoader;

    public TCCLSwitchingInvocationHandler(Object service) {
      myService = service;
      myClassLoader = service.getClass().getClassLoader();
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      Thread thread = Thread.currentThread();
      ClassLoader ccl = thread.getContextClassLoader();
      thread.setContextClassLoader(myClassLoader);
      try {
        return method.invoke(myService, args);
      } catch (InvocationTargetException e) {
        throw e.getCause();
      } finally {
        thread.setContextClassLoader(ccl);
      }
    }
  }

  public static  T withThreadContextClassLoaderOf(@NotNull Object object, @NotNull CallableE code) throws E {
    Thread thread = Thread.currentThread();
    ClassLoader ccl = thread.getContextClassLoader();
    thread.setContextClassLoader((object instanceof Class ? (Class)object : object.getClass()).getClassLoader());
    try {
      return code.call();
    } finally {
      thread.setContextClassLoader(ccl);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy