1 package com.atlassian.plugin.osgi.hostcomponents.impl;
2
3 import com.atlassian.plugin.hostcontainer.HostContainer;
4 import com.atlassian.plugin.osgi.hostcomponents.ComponentRegistrar;
5 import com.atlassian.plugin.osgi.hostcomponents.ContextClassLoaderStrategy;
6 import com.atlassian.plugin.osgi.hostcomponents.HostComponentRegistration;
7 import com.atlassian.plugin.osgi.hostcomponents.InstanceBuilder;
8 import com.atlassian.plugin.osgi.hostcomponents.PropertyBuilder;
9
10 import org.osgi.framework.BundleContext;
11 import org.osgi.framework.ServiceRegistration;
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14
15 import java.lang.reflect.InvocationHandler;
16 import java.lang.reflect.InvocationTargetException;
17 import java.lang.reflect.Method;
18 import java.lang.reflect.Proxy;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.concurrent.CopyOnWriteArrayList;
24
25
26
27
28 public class DefaultComponentRegistrar implements ComponentRegistrar
29 {
30 private static final Logger log = LoggerFactory.getLogger(DefaultComponentRegistrar.class);
31
32 private final List<HostComponentRegistration> registry = new CopyOnWriteArrayList<HostComponentRegistration>();
33
34 public InstanceBuilder register(final Class<?>... mainInterfaces)
35 {
36 final Registration reg = new Registration(mainInterfaces);
37 registry.add(reg);
38 return new DefaultInstanceBuilder(reg);
39 }
40
41 public List<ServiceRegistration> writeRegistry(final BundleContext ctx)
42 {
43 final ArrayList<ServiceRegistration> services = new ArrayList<ServiceRegistration>();
44
45 for (final HostComponentRegistration reg : new ArrayList<HostComponentRegistration>(registry))
46 {
47 if (Arrays.asList(reg.getMainInterfaceClasses()).contains(HostContainer.class))
48 {
49 log.warn("Cannot register a HostContainer as a host component, skipping");
50 registry.remove(reg);
51 continue;
52 }
53
54 final String[] names = reg.getMainInterfaces();
55
56 reg.getProperties().put(HOST_COMPONENT_FLAG, Boolean.TRUE.toString());
57
58
59 final String beanName = reg.getProperties().get(PropertyBuilder.BEAN_NAME);
60 if (beanName == null)
61 {
62 String genKey = String.valueOf(Arrays.asList(reg.getMainInterfaces()).hashCode());
63 reg.getProperties().put(PropertyBuilder.BEAN_NAME, "hostComponent-"+genKey);
64 }
65
66 if (log.isDebugEnabled())
67 {
68 log.debug("Registering: " + Arrays.asList(names) + " instance " + reg.getInstance() + "with properties: " + reg.getProperties());
69 }
70
71 if (names.length == 0)
72 {
73 log.warn("Host component " + beanName + " of instance " + reg.getInstance() + " has no interfaces");
74 }
75
76 Object service = reg.getInstance();
77 if (!ContextClassLoaderStrategy.USE_PLUGIN.name().equals(reg.getProperties().get(PropertyBuilder.CONTEXT_CLASS_LOADER_STRATEGY)))
78 {
79 service = wrapService(reg.getMainInterfaceClasses(), reg.getInstance());
80 }
81
82 final ServiceRegistration sreg = ctx.registerService(names, service, reg.getProperties());
83 if (sreg != null)
84 {
85 services.add(sreg);
86 }
87 }
88 return Collections.unmodifiableList(services);
89 }
90
91 public List<HostComponentRegistration> getRegistry()
92 {
93 return Collections.unmodifiableList(registry);
94 }
95
96
97
98
99
100
101
102
103
104 protected Object wrapService(final Class<?>[] interfaces, final Object service)
105 {
106 return Proxy.newProxyInstance(getClass().getClassLoader(), interfaces, new ContextClassLoaderSettingInvocationHandler(service));
107 }
108
109
110
111
112
113 private static class ContextClassLoaderSettingInvocationHandler implements InvocationHandler
114 {
115 private final Object service;
116
117 private final ClassLoader serviceClassLoader;
118
119 ContextClassLoaderSettingInvocationHandler(final Object service)
120 {
121 this.service = service;
122
123
124 this.serviceClassLoader = service.getClass().getClassLoader();
125 }
126
127 public Object invoke(final Object o, final Method method, final Object[] objects) throws Throwable
128 {
129 final Thread thread = Thread.currentThread();
130 final ClassLoader ccl = thread.getContextClassLoader();
131 try
132 {
133 thread.setContextClassLoader(serviceClassLoader);
134 return method.invoke(service, objects);
135 }
136 catch (final InvocationTargetException e)
137 {
138 throw e.getTargetException();
139 }
140 finally
141 {
142 thread.setContextClassLoader(ccl);
143 }
144 }
145 }
146 }