1 package com.atlassian.plugin.osgi.bridge.external;
2
3 import com.atlassian.plugin.PluginException;
4 import org.osgi.framework.BundleContext;
5 import org.osgi.framework.InvalidSyntaxException;
6 import org.osgi.framework.ServiceEvent;
7 import org.osgi.framework.ServiceListener;
8 import org.osgi.framework.ServiceReference;
9 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory;
11 import org.springframework.beans.factory.FactoryBean;
12 import org.springframework.beans.factory.InitializingBean;
13
14 import java.lang.reflect.InvocationHandler;
15 import java.lang.reflect.InvocationTargetException;
16 import java.lang.reflect.Method;
17 import java.lang.reflect.Proxy;
18
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static org.osgi.framework.ServiceEvent.REGISTERED;
21
22
23
24
25
26
27
28 public class HostComponentFactoryBean implements FactoryBean, InitializingBean
29 {
30 private BundleContext bundleContext;
31 private String filter;
32 private Object service;
33 private Class<?>[] interfaces;
34
35 @Override
36 public Object getObject() throws Exception
37 {
38 return findService();
39 }
40
41 @Override
42 public Class getObjectType()
43 {
44 return (findService() != null ? findService().getClass() : null);
45 }
46
47 @Override
48 public boolean isSingleton()
49 {
50 return true;
51 }
52
53 public void setBundleContext(BundleContext bundleContext)
54 {
55 this.bundleContext = bundleContext;
56 }
57
58
59
60
61
62
63 public void setFilter(String filter)
64 {
65 this.filter = filter;
66 }
67
68 public void setInterfaces(Class<?>[] interfaces)
69 {
70 this.interfaces = interfaces;
71 }
72
73
74
75
76
77
78
79
80 private Object findService() throws PluginException
81 {
82 return service;
83 }
84
85
86
87
88
89
90 private Object createHostComponentProxy()
91 {
92
93 return Proxy.newProxyInstance(bundleContext.getClass().getClassLoader(), interfaces, new DynamicServiceInvocationHandler(
94 bundleContext, filter));
95 }
96
97 @Override
98 public void afterPropertiesSet() throws Exception
99 {
100 checkNotNull(bundleContext);
101 checkNotNull(interfaces);
102 service = createHostComponentProxy();
103 }
104
105
106
107
108
109 static class DynamicServiceInvocationHandler implements InvocationHandler
110 {
111 private static final Logger log = LoggerFactory.getLogger(DynamicServiceInvocationHandler.class);
112 private volatile Object service;
113 private final String filter;
114
115
116 DynamicServiceInvocationHandler(final BundleContext bundleContext, final String filter)
117 {
118 this.filter = filter;
119 try
120 {
121 ServiceReference[] refs = bundleContext.getServiceReferences((String) null, filter);
122 if (refs != null && refs.length > 0)
123 {
124 service = bundleContext.getService(refs[0]);
125 }
126
127 bundleContext.addServiceListener(new ServiceListener()
128 {
129 @Override
130 public void serviceChanged(ServiceEvent serviceEvent)
131 {
132
133 if (REGISTERED == serviceEvent.getType())
134 {
135 if (log.isDebugEnabled())
136 {
137 log.debug("Updating the host component matching filter: " + filter);
138 }
139 service = bundleContext.getService(serviceEvent.getServiceReference());
140 }
141 }
142 }, filter);
143 }
144 catch (InvalidSyntaxException e)
145 {
146 throw new IllegalArgumentException("Invalid filter string: " + filter, e);
147 }
148 }
149
150 @Override
151 public Object invoke(final Object o, final Method method, final Object[] objects) throws Throwable
152 {
153 if (service == null)
154 {
155 throw new IllegalStateException("Unable to locate host component with filter: " + filter);
156 }
157 try
158 {
159 return method.invoke(service, objects);
160 }
161 catch (final InvocationTargetException e)
162 {
163 throw e.getTargetException();
164 }
165 }
166 }
167 }