PageRenderTime 37ms CodeModel.GetById 9ms RepoModel.GetById 1ms app.codeStats 0ms

/atlassian-plugins-osgi/src/main/java/com/atlassian/plugin/osgi/hostcomponents/impl/DefaultComponentRegistrar.java

https://bitbucket.org/purewind/atlassian-plugins
Java | 210 lines | 155 code | 40 blank | 15 comment | 14 complexity | 5ae756c80d50b22ed97ecf074b31c1d1 MD5 | raw file
  1. package com.atlassian.plugin.osgi.hostcomponents.impl;
  2. import com.atlassian.plugin.hostcontainer.HostContainer;
  3. import com.atlassian.plugin.osgi.hostcomponents.ComponentRegistrar;
  4. import com.atlassian.plugin.osgi.hostcomponents.ContextClassLoaderStrategy;
  5. import com.atlassian.plugin.osgi.hostcomponents.HostComponentRegistration;
  6. import com.atlassian.plugin.osgi.hostcomponents.InstanceBuilder;
  7. import com.atlassian.plugin.osgi.hostcomponents.PropertyBuilder;
  8. import com.atlassian.plugin.util.ContextClassLoaderSettingInvocationHandler;
  9. import com.google.common.base.Function;
  10. import com.google.common.collect.Maps;
  11. import org.osgi.framework.Bundle;
  12. import org.osgi.framework.BundleContext;
  13. import org.osgi.framework.ServiceFactory;
  14. import org.osgi.framework.ServiceRegistration;
  15. import org.slf4j.Logger;
  16. import org.slf4j.LoggerFactory;
  17. import java.lang.reflect.InvocationHandler;
  18. import java.lang.reflect.Method;
  19. import java.lang.reflect.Proxy;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.Collections;
  23. import java.util.List;
  24. import java.util.Map;
  25. import java.util.concurrent.CopyOnWriteArrayList;
  26. /**
  27. * Default component registrar that also can write registered host components into the OSGi service registry.
  28. */
  29. public class DefaultComponentRegistrar implements ComponentRegistrar {
  30. private static final Logger log = LoggerFactory.getLogger(DefaultComponentRegistrar.class);
  31. private final List<HostComponentRegistration> registry = new CopyOnWriteArrayList<HostComponentRegistration>();
  32. public InstanceBuilder register(final Class<?>... mainInterfaces) {
  33. final Registration reg = new Registration(mainInterfaces);
  34. registry.add(reg);
  35. return new DefaultInstanceBuilder(reg);
  36. }
  37. public List<ServiceRegistration> writeRegistry(final BundleContext ctx) {
  38. final ArrayList<ServiceRegistration> services = new ArrayList<ServiceRegistration>();
  39. for (final HostComponentRegistration reg : new ArrayList<HostComponentRegistration>(registry)) {
  40. if (Arrays.asList(reg.getMainInterfaceClasses()).contains(HostContainer.class)) {
  41. log.warn("Cannot register a HostContainer as a host component, skipping");
  42. registry.remove(reg);
  43. continue;
  44. }
  45. final String[] names = reg.getMainInterfaces();
  46. reg.getProperties().put(HOST_COMPONENT_FLAG, Boolean.TRUE.toString());
  47. // If no bean name specified, generate one that will be consistent across restarts
  48. final String beanName = reg.getProperties().get(PropertyBuilder.BEAN_NAME);
  49. if (beanName == null) {
  50. String genKey = String.valueOf(Arrays.asList(reg.getMainInterfaces()).hashCode());
  51. reg.getProperties().put(PropertyBuilder.BEAN_NAME, "hostComponent-" + genKey);
  52. }
  53. if (log.isDebugEnabled()) {
  54. log.debug("Registering: " + Arrays.asList(names) + " instance " + reg.getInstance() + "with properties: " + reg.getProperties());
  55. }
  56. if (names.length == 0) {
  57. log.warn("Host component " + beanName + " of instance " + reg.getInstance() + " has no interfaces");
  58. }
  59. Object service = reg.getInstance();
  60. if (!ContextClassLoaderStrategy.USE_PLUGIN.name().equals(reg.getProperties().get(PropertyBuilder.CONTEXT_CLASS_LOADER_STRATEGY))) {
  61. service = createContextClassLoaderSettingProxy(reg.getMainInterfaceClasses(), service);
  62. }
  63. if (Boolean.parseBoolean(reg.getProperties().get(PropertyBuilder.TRACK_BUNDLE))) {
  64. service = createTrackBundleProxy(reg.getMainInterfaceClasses(), service);
  65. }
  66. final ServiceRegistration sreg = ctx.registerService(names, service, reg.getProperties());
  67. if (sreg != null) {
  68. services.add(sreg);
  69. }
  70. }
  71. return Collections.unmodifiableList(services);
  72. }
  73. public List<HostComponentRegistration> getRegistry() {
  74. return Collections.unmodifiableList(registry);
  75. }
  76. /**
  77. * Wraps the service in a dynamic proxy that ensures all methods are executed with the object class's class loader
  78. * as the context class loader
  79. *
  80. * @param interfaces The interfaces to proxy
  81. * @param service The instance to proxy
  82. * @return A proxy that wraps the service
  83. */
  84. private Object createContextClassLoaderSettingProxy(final Class<?>[] interfaces, final Object service) {
  85. final Function<Object, Object> transformer = new Function<Object, Object>() {
  86. public Object apply(final Object service) {
  87. return Proxy.newProxyInstance(DefaultComponentRegistrar.class.getClassLoader(), interfaces,
  88. new ContextClassLoaderSettingInvocationHandler(service));
  89. }
  90. };
  91. if (!(service instanceof ServiceFactory)) {
  92. return transformer.apply(service);
  93. }
  94. return new TransformingServiceFactory((ServiceFactory) service) {
  95. @Override
  96. protected Object transform(Bundle bundle, ServiceRegistration registration, Object service) {
  97. return transformer.apply(service);
  98. }
  99. };
  100. }
  101. private ServiceFactory createTrackBundleProxy(final Class<?>[] interfaces, final Object service) {
  102. final ServiceFactory delegate = service instanceof ServiceFactory ?
  103. (ServiceFactory) service :
  104. new InstanceServiceFactory(service);
  105. return new TransformingServiceFactory(delegate) {
  106. @Override
  107. protected Object transform(final Bundle bundle, final ServiceRegistration registration, final Object service) {
  108. return Proxy.newProxyInstance(DefaultComponentRegistrar.class.getClassLoader(), interfaces,
  109. new BundleTrackingInvocationHandler(bundle, service));
  110. }
  111. };
  112. }
  113. private static class BundleTrackingInvocationHandler implements InvocationHandler {
  114. private final Bundle bundle;
  115. private final Object service;
  116. private BundleTrackingInvocationHandler(Bundle bundle, Object service) {
  117. this.bundle = bundle;
  118. this.service = service;
  119. }
  120. @Override
  121. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  122. Bundle original = CallingBundleStore.get();
  123. try {
  124. CallingBundleStore.set(bundle);
  125. return method.invoke(service, args);
  126. } finally {
  127. CallingBundleStore.set(original);
  128. }
  129. }
  130. }
  131. private static class InstanceServiceFactory implements ServiceFactory {
  132. private final Object service;
  133. private InstanceServiceFactory(final Object service) {
  134. this.service = service;
  135. }
  136. @Override
  137. public Object getService(final Bundle bundle, final ServiceRegistration registration) {
  138. return service;
  139. }
  140. @Override
  141. public void ungetService(final Bundle bundle, final ServiceRegistration registration, final Object service) {
  142. // no-op
  143. }
  144. }
  145. private static abstract class TransformingServiceFactory implements ServiceFactory {
  146. private final ServiceFactory delegate;
  147. private final Map<Long, Object> bundleIdToOriginalService;
  148. private TransformingServiceFactory(ServiceFactory delegate) {
  149. this.delegate = delegate;
  150. this.bundleIdToOriginalService = Maps.newConcurrentMap();
  151. }
  152. @Override
  153. public final Object getService(final Bundle bundle, final ServiceRegistration registration) {
  154. final Object service = delegate.getService(bundle, registration);
  155. final Object transformed = transform(bundle, registration, service);
  156. // Store the original service after it has been transformed
  157. // in case the transformer throws an exception
  158. bundleIdToOriginalService.put(bundle.getBundleId(), service);
  159. return transformed;
  160. }
  161. @Override
  162. public final void ungetService(final Bundle bundle, final ServiceRegistration registration, final Object transformed) {
  163. final Object service = bundleIdToOriginalService.remove(bundle.getBundleId());
  164. if (service != null) {
  165. delegate.ungetService(bundle, registration, service);
  166. }
  167. }
  168. protected abstract Object transform(Bundle bundle, ServiceRegistration registration, Object service);
  169. }
  170. }