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 com.atlassian.plugin.util.ContextClassLoaderSettingInvocationHandler;
11 import com.google.common.base.Function;
12 import com.google.common.collect.Maps;
13 import org.osgi.framework.Bundle;
14 import org.osgi.framework.BundleContext;
15 import org.osgi.framework.ServiceFactory;
16 import org.osgi.framework.ServiceRegistration;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
19
20 import java.lang.reflect.InvocationHandler;
21 import java.lang.reflect.Method;
22 import java.lang.reflect.Proxy;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.concurrent.CopyOnWriteArrayList;
29
30
31
32
33 public class DefaultComponentRegistrar implements ComponentRegistrar
34 {
35 private static final Logger log = LoggerFactory.getLogger(DefaultComponentRegistrar.class);
36
37 private final List<HostComponentRegistration> registry = new CopyOnWriteArrayList<HostComponentRegistration>();
38
39 public InstanceBuilder register(final Class<?>... mainInterfaces)
40 {
41 final Registration reg = new Registration(mainInterfaces);
42 registry.add(reg);
43 return new DefaultInstanceBuilder(reg);
44 }
45
46 public List<ServiceRegistration> writeRegistry(final BundleContext ctx)
47 {
48 final ArrayList<ServiceRegistration> services = new ArrayList<ServiceRegistration>();
49
50 for (final HostComponentRegistration reg : new ArrayList<HostComponentRegistration>(registry))
51 {
52 if (Arrays.asList(reg.getMainInterfaceClasses()).contains(HostContainer.class))
53 {
54 log.warn("Cannot register a HostContainer as a host component, skipping");
55 registry.remove(reg);
56 continue;
57 }
58
59 final String[] names = reg.getMainInterfaces();
60
61 reg.getProperties().put(HOST_COMPONENT_FLAG, Boolean.TRUE.toString());
62
63
64 final String beanName = reg.getProperties().get(PropertyBuilder.BEAN_NAME);
65 if (beanName == null)
66 {
67 String genKey = String.valueOf(Arrays.asList(reg.getMainInterfaces()).hashCode());
68 reg.getProperties().put(PropertyBuilder.BEAN_NAME, "hostComponent-"+genKey);
69 }
70
71 if (log.isDebugEnabled())
72 {
73 log.debug("Registering: " + Arrays.asList(names) + " instance " + reg.getInstance() + "with properties: " + reg.getProperties());
74 }
75
76 if (names.length == 0)
77 {
78 log.warn("Host component " + beanName + " of instance " + reg.getInstance() + " has no interfaces");
79 }
80
81 Object service = reg.getInstance();
82
83 if (!ContextClassLoaderStrategy.USE_PLUGIN.name().equals(reg.getProperties().get(PropertyBuilder.CONTEXT_CLASS_LOADER_STRATEGY)))
84 {
85 service = createContextClassLoaderSettingProxy(reg.getMainInterfaceClasses(), service);
86 }
87
88 if (Boolean.parseBoolean(reg.getProperties().get(PropertyBuilder.TRACK_BUNDLE)))
89 {
90 service = createTrackBundleProxy(reg.getMainInterfaceClasses(), service);
91 }
92
93 final ServiceRegistration sreg = ctx.registerService(names, service, reg.getProperties());
94 if (sreg != null)
95 {
96 services.add(sreg);
97 }
98 }
99 return Collections.unmodifiableList(services);
100 }
101
102 public List<HostComponentRegistration> getRegistry()
103 {
104 return Collections.unmodifiableList(registry);
105 }
106
107
108
109
110
111
112
113
114
115 private Object createContextClassLoaderSettingProxy(final Class<?>[] interfaces, final Object service)
116 {
117 final Function<Object, Object> transformer = new Function<Object, Object>()
118 {
119 public Object apply(final Object service)
120 {
121 return Proxy.newProxyInstance(DefaultComponentRegistrar.class.getClassLoader(), interfaces,
122 new ContextClassLoaderSettingInvocationHandler(service));
123 }
124 };
125
126 if (!(service instanceof ServiceFactory))
127 {
128 return transformer.apply(service);
129 }
130 return new TransformingServiceFactory((ServiceFactory) service)
131 {
132 @Override
133 protected Object transform(Bundle bundle, ServiceRegistration registration, Object service)
134 {
135 return transformer.apply(service);
136 }
137 };
138
139 }
140
141 private ServiceFactory createTrackBundleProxy(final Class<?>[] interfaces, final Object service)
142 {
143 final ServiceFactory delegate = service instanceof ServiceFactory ?
144 (ServiceFactory) service :
145 new InstanceServiceFactory(service);
146
147 return new TransformingServiceFactory(delegate)
148 {
149 @Override
150 protected Object transform(final Bundle bundle, final ServiceRegistration registration, final Object service)
151 {
152 return Proxy.newProxyInstance(DefaultComponentRegistrar.class.getClassLoader(), interfaces,
153 new BundleTrackingInvocationHandler(bundle, service));
154 }
155 };
156 }
157
158 private static class BundleTrackingInvocationHandler implements InvocationHandler
159 {
160
161 private final Bundle bundle;
162 private final Object service;
163
164 private BundleTrackingInvocationHandler(Bundle bundle, Object service)
165 {
166 this.bundle = bundle;
167 this.service = service;
168 }
169
170 @Override
171 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
172 {
173 Bundle original = CallingBundleStore.get();
174 try
175 {
176 CallingBundleStore.set(bundle);
177 return method.invoke(service, args);
178 }
179 finally
180 {
181 CallingBundleStore.set(original);
182 }
183 }
184 }
185
186 private static class InstanceServiceFactory implements ServiceFactory
187 {
188
189 private final Object service;
190
191 private InstanceServiceFactory(final Object service)
192 {
193 this.service = service;
194 }
195
196 @Override
197 public Object getService(final Bundle bundle, final ServiceRegistration registration)
198 {
199 return service;
200 }
201
202 @Override
203 public void ungetService(final Bundle bundle, final ServiceRegistration registration, final Object service)
204 {
205
206 }
207 }
208
209 private static abstract class TransformingServiceFactory implements ServiceFactory
210 {
211
212 private final ServiceFactory delegate;
213 private final Map<Long, Object> bundleIdToOriginalService;
214
215 private TransformingServiceFactory(ServiceFactory delegate)
216 {
217 this.delegate = delegate;
218 this.bundleIdToOriginalService = Maps.newConcurrentMap();
219 }
220
221
222 @Override
223 public final Object getService(final Bundle bundle, final ServiceRegistration registration)
224 {
225 final Object service = delegate.getService(bundle, registration);
226 final Object transformed = transform(bundle, registration, service);
227
228
229 bundleIdToOriginalService.put(bundle.getBundleId(), service);
230 return transformed;
231 }
232
233 @Override
234 public final void ungetService(final Bundle bundle, final ServiceRegistration registration, final Object transformed)
235 {
236 final Object service = bundleIdToOriginalService.remove(bundle.getBundleId());
237 if (service != null)
238 {
239 delegate.ungetService(bundle, registration, service);
240 }
241 }
242
243 protected abstract Object transform(Bundle bundle, ServiceRegistration registration, Object service);
244
245 }
246
247 }