1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.osgi.service.importer.support;
18
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.osgi.framework.BundleContext;
22 import org.osgi.framework.Filter;
23 import org.springframework.beans.factory.BeanClassLoaderAware;
24 import org.springframework.beans.factory.BeanNameAware;
25 import org.springframework.beans.factory.DisposableBean;
26 import org.springframework.beans.factory.FactoryBean;
27 import org.springframework.beans.factory.InitializingBean;
28 import org.springframework.osgi.context.BundleContextAware;
29 import org.springframework.osgi.service.exporter.OsgiServicePropertiesResolver;
30 import org.springframework.osgi.service.importer.OsgiServiceLifecycleListener;
31 import org.springframework.osgi.util.OsgiFilterUtils;
32 import org.springframework.osgi.util.internal.ClassUtils;
33 import org.springframework.util.Assert;
34 import org.springframework.util.ObjectUtils;
35
36 /**
37 * Base class for importing OSGi services. Provides the common properties and
38 * contracts between importers.
39 *
40 * @author Costin Leau
41 * @author Adrian Colyer
42 * @author Hal Hildebrand
43 */
44 public abstract class AbstractOsgiServiceImportFactoryBean implements FactoryBean, InitializingBean, DisposableBean,
45 BundleContextAware, BeanClassLoaderAware, BeanNameAware {
46
47 private static final Log log = LogFactory.getLog(AbstractOsgiServiceImportFactoryBean.class);
48
49 /** context classloader */
50 private ClassLoader classLoader;
51
52 private BundleContext bundleContext;
53
54 private ImportContextClassLoader contextClassLoader = ImportContextClassLoader.CLIENT;
55
56
57 private Class[] interfaces;
58
59
60 private String filter;
61
62
63
64 private Filter unifiedFilter;
65
66
67 private OsgiServiceLifecycleListener[] listeners;
68
69 /** Service Bean property of the OSGi service * */
70 private String serviceBeanName;
71
72 private Cardinality cardinality;
73
74 /** bean name */
75 private String beanName = "";
76
77
78 public void afterPropertiesSet() {
79 Assert.notNull(this.bundleContext, "Required 'bundleContext' property was not set.");
80 Assert.notNull(classLoader, "Required 'classLoader' property was not set.");
81 Assert.notNull(interfaces, "Required 'interfaces' property was not set.");
82
83 Assert.isTrue(!ClassUtils.containsUnrelatedClasses(interfaces),
84 "more then one concrete class specified; cannot create proxy.");
85
86 this.listeners = (listeners == null ? new OsgiServiceLifecycleListener[0] : listeners);
87
88 getUnifiedFilter();
89
90 Assert.notNull(interfaces, "Required serviceTypes property not specified.");
91 }
92
93 /**
94 * Assembles the configuration properties into one unified OSGi filter. Note
95 * that this implementation creates the filter on the first call and caches
96 * it afterwards.
97 *
98 * @return unified filter based on this factory bean configuration
99 */
100 public Filter getUnifiedFilter() {
101 if (unifiedFilter != null) {
102 return unifiedFilter;
103 }
104
105 String filterWithClasses = OsgiFilterUtils.unifyFilter(interfaces, filter);
106
107 boolean trace = log.isTraceEnabled();
108 if (trace)
109 log.trace("Unified classes=" + ObjectUtils.nullSafeToString(interfaces) + " and filter=[" + filter
110 + "] in=[" + filterWithClasses + "]");
111
112
113 String filterWithServiceBeanName = OsgiFilterUtils.unifyFilter(
114 OsgiServicePropertiesResolver.BEAN_NAME_PROPERTY_KEY, new String[] { serviceBeanName }, filterWithClasses);
115
116 if (trace)
117 log.trace("Unified serviceBeanName [" + ObjectUtils.nullSafeToString(serviceBeanName) + "] and filter=["
118 + filterWithClasses + "] in=[" + filterWithServiceBeanName + "]");
119
120
121 unifiedFilter = OsgiFilterUtils.createFilter(filterWithServiceBeanName);
122
123 return unifiedFilter;
124 }
125
126 /**
127 * Sets the classes that the imported service advertises.
128 *
129 * @param interfaces array of advertised classes.
130 */
131 public void setInterfaces(Class[] interfaces) {
132 this.interfaces = interfaces;
133 }
134
135 /**
136 * Sets the thread context class loader management strategy to use for
137 * services imported by this service. By default
138 * {@link ImportContextClassLoader#CLIENT} is used.
139 *
140 * @param contextClassLoader import context class loader management strategy
141 * @see ImportContextClassLoader
142 */
143 public void setContextClassLoader(ImportContextClassLoader contextClassLoader) {
144 Assert.notNull(contextClassLoader);
145 this.contextClassLoader = contextClassLoader;
146 }
147
148 public void setBundleContext(BundleContext context) {
149 this.bundleContext = context;
150 }
151
152 /**
153 * Sets the OSGi service filter. The filter will be concatenated with the
154 * rest of the configuration properties specified (such as interfaces) so
155 * there is no need to include them in the filter.
156 *
157 * @param filter OSGi filter describing the importing OSGi service
158 */
159 public void setFilter(String filter) {
160 this.filter = filter;
161 }
162
163 /**
164 * Sets the lifecycle listeners interested in receiving events for this
165 * importer.
166 *
167 * @param listeners importer listeners
168 */
169 public void setListeners(OsgiServiceLifecycleListener[] listeners) {
170 this.listeners = listeners;
171 }
172
173 /**
174 * Sets the OSGi service bean name. This setting should be normally used
175 * when the imported service has been exported by Spring DM exporter. You
176 * may specify additional filtering criteria if needed (using the filter
177 * property) but this is not required.
178 *
179 * @param serviceBeanName importer service bean name
180 */
181 public void setServiceBeanName(String serviceBeanName) {
182 this.serviceBeanName = serviceBeanName;
183 }
184
185 /**
186 * {@inheritDoc}
187 *
188 * This method is called automatically by the container.
189 */
190 public void setBeanClassLoader(ClassLoader classLoader) {
191 this.classLoader = classLoader;
192 }
193
194 /**
195 * Returns the class loader used by this FactoryBean.
196 *
197 * @return factory bean class loader
198 */
199 public ClassLoader getBeanClassLoader() {
200 return classLoader;
201 }
202
203 /**
204 * Returns the bundleContext used by this FactoryBean.
205 *
206 * @return factory bean class loader
207 */
208 public BundleContext getBundleContext() {
209 return bundleContext;
210 }
211
212 /**
213 * Returns the interfaces used for discovering the imported service(s).
214 *
215 * @return interfaces advertised by services in the OSGi space
216 */
217 public Class[] getInterfaces() {
218 return interfaces;
219 }
220
221 /**
222 * Returns the filter describing the imported service(s).
223 *
224 * @return filter describing the imported service(s)
225 */
226 public String getFilter() {
227 return filter;
228 }
229
230 /**
231 * Returns the listeners interested in receiving events for this importer.
232 *
233 * @return lifecycle listeners used by this importer
234 */
235 public OsgiServiceLifecycleListener[] getListeners() {
236 return listeners;
237 }
238
239 /**
240 * Returns the context class loader management strategy.
241 *
242 * @return the context class loader management strategy
243 */
244 public ImportContextClassLoader getContextClassLoader() {
245 return contextClassLoader;
246 }
247
248 /**
249 * Returns the cardinality used by this importer.
250 *
251 * @return importer cardinality
252 */
253 public Cardinality getCardinality() {
254 return cardinality;
255 }
256
257 /**
258 * Sets the importer cardinality (0..1, 1..1, 0..N, or 1..N). Default is
259 * 1..X.
260 *
261 * @param cardinality importer cardinality.
262 */
263 public void setCardinality(Cardinality cardinality) {
264 Assert.notNull(cardinality);
265 this.cardinality = cardinality;
266 }
267
268 /**
269 * Returns the bean name associated with the instance of this class (when
270 * running inside the Spring container).
271 *
272 * @return component bean name
273 */
274 public String getBeanName() {
275 return beanName;
276 }
277
278 public void setBeanName(String name) {
279 beanName = name;
280 }
281 }