blob: 659ec4905fd134d00fc7f311306fdd28813eb46d [file] [log] [blame]
Marcel Offermansa962bc92009-11-21 17:59:33 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Pierre De Ropae4a5db2009-12-04 22:08:05 +000019package org.apache.felix.dm;
Marcel Offermansa962bc92009-11-21 17:59:33 +000020
21import java.util.ArrayList;
22import java.util.Collections;
23import java.util.List;
24
Pierre De Ropae4a5db2009-12-04 22:08:05 +000025import org.apache.felix.dm.dependencies.BundleDependency;
26import org.apache.felix.dm.dependencies.ConfigurationDependency;
Pierre De Ropa0204f52010-03-06 22:23:57 +000027import org.apache.felix.dm.dependencies.PropertyMetaData;
Pierre De Ropae4a5db2009-12-04 22:08:05 +000028import org.apache.felix.dm.dependencies.ResourceDependency;
29import org.apache.felix.dm.dependencies.ServiceDependency;
30import org.apache.felix.dm.dependencies.TemporalServiceDependency;
Pierre De Rop34231582010-05-23 20:05:16 +000031import org.apache.felix.dm.impl.AdapterServiceImpl;
Pierre De Rop19476fe2010-05-23 08:13:58 +000032import org.apache.felix.dm.impl.AspectServiceImpl;
Pierre De Rop13dd63d2010-05-23 21:58:28 +000033import org.apache.felix.dm.impl.BundleAdapterServiceImpl;
Pierre De Rop3e100372010-05-24 12:43:44 +000034import org.apache.felix.dm.impl.FactoryConfigurationAdapterServiceImpl;
Pierre De Ropae4a5db2009-12-04 22:08:05 +000035import org.apache.felix.dm.impl.Logger;
Pierre De Rop445ddec2010-05-23 21:05:27 +000036import org.apache.felix.dm.impl.ResourceAdapterServiceImpl;
Pierre De Ropae4a5db2009-12-04 22:08:05 +000037import org.apache.felix.dm.impl.ServiceImpl;
38import org.apache.felix.dm.impl.dependencies.BundleDependencyImpl;
39import org.apache.felix.dm.impl.dependencies.ConfigurationDependencyImpl;
40import org.apache.felix.dm.impl.dependencies.ResourceDependencyImpl;
41import org.apache.felix.dm.impl.dependencies.ServiceDependencyImpl;
42import org.apache.felix.dm.impl.dependencies.TemporalServiceDependencyImpl;
Pierre De Ropa0204f52010-03-06 22:23:57 +000043import org.apache.felix.dm.impl.metatype.PropertyMetaDataImpl;
Marcel Offermans4fd903f2009-12-29 09:18:05 +000044import org.apache.felix.dm.resources.Resource;
Pierre De Ropae4a5db2009-12-04 22:08:05 +000045import org.apache.felix.dm.service.Service;
Marcel Offermansb8405a52009-12-22 19:01:31 +000046import org.osgi.framework.BundleContext;
Marcel Offermansa962bc92009-11-21 17:59:33 +000047
48/**
Marcel Offermans4fd903f2009-12-29 09:18:05 +000049 * The dependency manager manages all services and their dependencies. Using
50 * this API you can declare all services and their dependencies. Under normal
51 * circumstances, you get passed an instance of this class through the
52 * <code>DependencyActivatorBase</code> subclass you use as your
53 * <code>BundleActivator</code>, but it is also possible to create your
54 * own instance.
Marcel Offermansa962bc92009-11-21 17:59:33 +000055 *
56 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
57 */
58public class DependencyManager {
Marcel Offermansad760672010-03-03 15:30:01 +000059 public static final String ASPECT = "org.apache.felix.dependencymanager.aspect";
Marcel Offermansa962bc92009-11-21 17:59:33 +000060 private final BundleContext m_context;
61 private final Logger m_logger;
62 private List m_services = Collections.synchronizedList(new ArrayList());
63
64 /**
Marcel Offermans4fd903f2009-12-29 09:18:05 +000065 * Creates a new dependency manager. You need to supply the
66 * <code>BundleContext</code> to be used by the dependency
67 * manager to register services and communicate with the
68 * framework.
Marcel Offermansa962bc92009-11-21 17:59:33 +000069 *
70 * @param context the bundle context
Marcel Offermansa962bc92009-11-21 17:59:33 +000071 */
Pierre De Ropae4a5db2009-12-04 22:08:05 +000072 public DependencyManager(BundleContext context) {
73 this(context, new Logger(context));
74 }
75
Marcel Offermans4fd903f2009-12-29 09:18:05 +000076 DependencyManager(BundleContext context, Logger logger) {
Marcel Offermansa962bc92009-11-21 17:59:33 +000077 m_context = context;
78 m_logger = logger;
79 }
Pierre De Ropae4a5db2009-12-04 22:08:05 +000080
Marcel Offermansa962bc92009-11-21 17:59:33 +000081 /**
82 * Adds a new service to the dependency manager. After the service was added
83 * it will be started immediately.
84 *
85 * @param service the service to add
86 */
87 public void add(Service service) {
88 m_services.add(service);
89 service.start();
90 }
91
92 /**
93 * Removes a service from the dependency manager. Before the service is removed
94 * it is stopped first.
95 *
96 * @param service the service to remove
97 */
98 public void remove(Service service) {
99 service.stop();
100 m_services.remove(service);
101 }
102
103 /**
104 * Creates a new service.
105 *
106 * @return the new service
107 */
108 public Service createService() {
109 return new ServiceImpl(m_context, this, m_logger);
110 }
111
112 /**
113 * Creates a new service dependency.
114 *
115 * @return the service dependency
116 */
117 public ServiceDependency createServiceDependency() {
Pierre De Ropae4a5db2009-12-04 22:08:05 +0000118 return new ServiceDependencyImpl(m_context, m_logger);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000119 }
120
Marcel Offermans74363c32009-11-23 19:56:08 +0000121 /**
122 * Creates a new temporal service dependency.
123 *
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000124 * @return a new temporal service dependency
Marcel Offermans74363c32009-11-23 19:56:08 +0000125 */
126 public TemporalServiceDependency createTemporalServiceDependency() {
Pierre De Ropae4a5db2009-12-04 22:08:05 +0000127 return new TemporalServiceDependencyImpl(m_context, m_logger);
Marcel Offermans74363c32009-11-23 19:56:08 +0000128 }
Marcel Offermans2925f172009-12-02 13:03:39 +0000129
130 /**
131 * Creates a new configuration dependency.
132 *
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000133 * @return the configuration dependency
Marcel Offermans2925f172009-12-02 13:03:39 +0000134 */
Marcel Offermansa962bc92009-11-21 17:59:33 +0000135 public ConfigurationDependency createConfigurationDependency() {
Pierre De Ropae4a5db2009-12-04 22:08:05 +0000136 return new ConfigurationDependencyImpl(m_context, m_logger);
Marcel Offermansa962bc92009-11-21 17:59:33 +0000137 }
138
Marcel Offermans2925f172009-12-02 13:03:39 +0000139 /**
Pierre De Ropa0204f52010-03-06 22:23:57 +0000140 * Creates a new configuration property MetaData.
141 * @return a new Configuration property MetaData.
142 */
143 public PropertyMetaData createPropertyMetaData() {
144 return new PropertyMetaDataImpl();
145 }
146
147 /**
Marcel Offermans2925f172009-12-02 13:03:39 +0000148 * Creates a new bundle dependency.
149 *
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000150 * @return a new BundleDependency instance.
Marcel Offermans2925f172009-12-02 13:03:39 +0000151 */
Marcel Offermansd66c5ce2009-11-26 09:58:44 +0000152 public BundleDependency createBundleDependency() {
Pierre De Ropae4a5db2009-12-04 22:08:05 +0000153 return new BundleDependencyImpl(m_context, m_logger);
Marcel Offermansd66c5ce2009-11-26 09:58:44 +0000154 }
Marcel Offermans2925f172009-12-02 13:03:39 +0000155
156 /**
157 * Creates a new resource dependency.
158 *
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000159 * @return the resource dependency
Marcel Offermans2925f172009-12-02 13:03:39 +0000160 */
161 public ResourceDependency createResourceDependency() {
Pierre De Ropae4a5db2009-12-04 22:08:05 +0000162 return new ResourceDependencyImpl(m_context, m_logger);
Marcel Offermans2925f172009-12-02 13:03:39 +0000163 }
Marcel Offermans80eeafe2009-12-01 22:12:26 +0000164
Marcel Offermans2925f172009-12-02 13:03:39 +0000165 /**
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000166 * Creates a new aspect. The aspect will be applied to any service that
167 * matches the specified interface and filter. For each matching service
168 * an aspect will be created based on the aspect implementation class.
169 * The aspect will be registered with the same interface and properties
170 * as the original service, plus any extra properties you supply here.
171 * It will also inherit all dependencies, and if you declare the original
172 * service as a member it will be injected.
Marcel Offermans2925f172009-12-02 13:03:39 +0000173 *
Pierre De Rop19476fe2010-05-23 08:13:58 +0000174 * <h3>Usage Example</h3>
175 *
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000176 * <blockquote><pre>
Pierre De Rop19476fe2010-05-23 08:13:58 +0000177 * manager.createAspectService(ExistingService.class, "(foo=bar)", 10, "m_aspect")
178 * .setImplementation(ExistingServiceAspect.class)
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000179 * .setServiceProperties(new Hashtable() {{ put("additional", "properties"); }});
180 * </pre></blockquote>
Pierre De Rop19476fe2010-05-23 08:13:58 +0000181 *
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000182 * @param serviceInterface the service interface to apply the aspect to
183 * @param serviceFilter the filter condition to use with the service interface
Pierre De Rop19476fe2010-05-23 08:13:58 +0000184 * @param ranking the level used to organize the aspect chain ordering
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000185 * @param attributeName the aspect implementation field name where to inject original service.
Pierre De Rop19476fe2010-05-23 08:13:58 +0000186 * If null, any field matching the original service will be injected.
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000187 * @return a service that acts as a factory for generating aspects
Marcel Offermans2925f172009-12-02 13:03:39 +0000188 */
Pierre De Rop19476fe2010-05-23 08:13:58 +0000189 public Service createAspectService(Class serviceInterface, String serviceFilter, int ranking, String attributeName) {
190 return new AspectServiceImpl(this, serviceInterface, serviceFilter, ranking, attributeName);
Marcel Offermans80eeafe2009-12-01 22:12:26 +0000191 }
Pierre De Rop19476fe2010-05-23 08:13:58 +0000192
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000193 /**
194 * Creates a new adapter. The adapter will be applied to any service that
195 * matches the specified interface and filter. For each matching service
196 * an adapter will be created based on the adapter implementation class.
197 * The adapter will be registered with the specified interface and existing properties
198 * from the original service plus any extra properties you supply here.
199 * It will also inherit all dependencies, and if you declare the original
200 * service as a member it will be injected.
201 *
Pierre De Rop34231582010-05-23 20:05:16 +0000202 * <h3>Usage Example</h3>
203 *
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000204 * <blockquote><pre>
Pierre De Rop34231582010-05-23 20:05:16 +0000205 * manager.createAdapterService(AdapteeService.class, "(foo=bar)")
Pierre De Rop445ddec2010-05-23 21:05:27 +0000206 * // The interface to use when registering adapter
Pierre De Rop34231582010-05-23 20:05:16 +0000207 * .setInterface(AdapterService.class, new Hashtable() {{ put("additional", "properties"); }})
208 * // the implementation of the adapter
209 * .setImplementation(AdapterImpl.class);
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000210 * </pre></blockquote>
Marcel Offermansd665eaf2010-02-16 15:56:35 +0000211 * @param serviceInterface the service interface to apply the adapter to
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000212 * @param serviceFilter the filter condition to use with the service interface
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000213 * @return a service that acts as a factory for generating adapters
214 */
Pierre De Rop34231582010-05-23 20:05:16 +0000215 public Service createAdapterService(Class serviceInterface, String serviceFilter) {
216 return new AdapterServiceImpl(this, serviceInterface, serviceFilter);
Marcel Offermans61a81142010-04-02 15:16:50 +0000217 }
Pierre De Rop34231582010-05-23 20:05:16 +0000218
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000219 /**
220 * Creates a new resource adapter. The adapter will be applied to any resource that
221 * matches the specified filter condition. For each matching resource
222 * an adapter will be created based on the adapter implementation class.
223 * The adapter will be registered with the specified interface and existing properties
224 * from the original resource plus any extra properties you supply here.
225 * It will also inherit all dependencies, and if you declare the original
226 * service as a member it will be injected.
227 *
Pierre De Rop445ddec2010-05-23 21:05:27 +0000228 * <h3>Usage Example</h3>
229 *
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000230 * <blockquote><pre>
Pierre De Rop445ddec2010-05-23 21:05:27 +0000231 * manager.createResourceAdapterService("(&(path=/test)(repository=TestRepository))", true)
232 * // The interface to use when registering adapter
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000233 * .setInterface(AdapterService.class.getName(), new Hashtable() {{ put("foo", "bar"); }})
Pierre De Rop445ddec2010-05-23 21:05:27 +0000234 * // the implementation of the adapter
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000235 * .setImplementation(AdapterServiceImpl.class);
236 * </pre></blockquote>
Pierre De Rop445ddec2010-05-23 21:05:27 +0000237 *
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000238 * @param resourceFilter the filter condition to use with the resource
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000239 * @param propagate <code>true</code> if properties from the resource should be propagated to the service
240 * @return a service that acts as a factory for generating resource adapters
241 * @see Resource
242 */
Pierre De Rop445ddec2010-05-23 21:05:27 +0000243 public Service createResourceAdapterService(String resourceFilter, boolean propagate) {
244 return new ResourceAdapterServiceImpl(this, resourceFilter, propagate);
Marcel Offermans61a81142010-04-02 15:16:50 +0000245 }
Pierre De Rop445ddec2010-05-23 21:05:27 +0000246
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000247 /**
248 * Creates a new bundle adapter. The adapter will be applied to any bundle that
249 * matches the specified bundle state mask and filter condition. For each matching
250 * bundle an adapter will be created based on the adapter implementation class.
251 * The adapter will be registered with the specified interface
252 *
253 * TODO and existing properties from the original resource plus any extra properties you supply here.
254 * It will also inherit all dependencies, and if you declare the original
255 * service as a member it will be injected.
256 *
Pierre De Rop13dd63d2010-05-23 21:58:28 +0000257 * <h3>Usage Example</h3>
258 *
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000259 * <blockquote><pre>
Pierre De Rop13dd63d2010-05-23 21:58:28 +0000260 * manager.createBundleAdapterService(Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE,
261 * "(Bundle-SymbolicName=org.apache.felix.dependencymanager)",
262 * true)
263 * // The interface to use when registering adapter
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000264 * .setInterface(AdapterService.class.getName(), new Hashtable() {{ put("foo", "bar"); }})
Pierre De Rop13dd63d2010-05-23 21:58:28 +0000265 * // the implementation of the adapter
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000266 * .setImplementation(AdapterServiceImpl.class);
267 * </pre></blockquote>
Pierre De Rop13dd63d2010-05-23 21:58:28 +0000268 *
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000269 * @param bundleStateMask the bundle state mask to apply
270 * @param bundleFilter the filter to apply to the bundle manifest
Marcel Offermansd665eaf2010-02-16 15:56:35 +0000271 * @param propagate <code>true</code> if properties from the bundle should be propagated to the service
Marcel Offermans4fd903f2009-12-29 09:18:05 +0000272 * @return a service that acts as a factory for generating bundle adapters
273 */
Pierre De Rop13dd63d2010-05-23 21:58:28 +0000274 public Service createBundleAdapterService(int bundleStateMask, String bundleFilter, boolean propagate) {
275 return new BundleAdapterServiceImpl(this, bundleStateMask, bundleFilter, propagate);
Marcel Offermans61a81142010-04-02 15:16:50 +0000276 }
Marcel Offermans80eeafe2009-12-01 22:12:26 +0000277
Marcel Offermansa962bc92009-11-21 17:59:33 +0000278 /**
Pierre De Ropef94c882010-04-17 18:23:35 +0000279 * Creates a new Managed Service Factory Configuration Adapter. For each new Config Admin factory configuration matching
280 * the factoryPid, an adapter will be created based on the adapter implementation class.
281 * The adapter will be registered with the specified interface, and with the specified adapter service properties.
282 * Depending on the <code>propagate</code> parameter, every public factory configuration properties
283 * (which don't start with ".") will be propagated along with the adapter service properties.
284 * It will also inherit all dependencies.
285 *
Pierre De Rop3e100372010-05-24 12:43:44 +0000286 * <h3>Usage Example</h3>
287 *
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000288 * <blockquote><pre>
Pierre De Rop3e100372010-05-24 12:43:44 +0000289 * manager.createFactoryConfigurationAdapterService("MyFactoryPid", "update", true)
290 * // The interface to use when registering adapter
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000291 * .setInterface(AdapterService.class.getName(), new Hashtable() {{ put("foo", "bar"); }})
Pierre De Rop3e100372010-05-24 12:43:44 +0000292 * // the implementation of the adapter
293 * .setImplementation(AdapterServiceImpl.class);
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000294 * </pre></blockquote>
295 *
Pierre De Ropef94c882010-04-17 18:23:35 +0000296 * @param factoryPid the pid matching the factory configuration
297 * @param update the adapter method name that will be notified when the factory configuration is created/updated.
Pierre De Ropef94c882010-04-17 18:23:35 +0000298 * @param propagate true if public factory configuration should be propagated to the adapter service properties
299 * @return a service that acts as a factory for generating the managed service factory configuration adapter
300 */
Pierre De Rop3e100372010-05-24 12:43:44 +0000301 public Service createFactoryConfigurationAdapterService(String factoryPid, String update, boolean propagate) {
302 return new FactoryConfigurationAdapterServiceImpl(this, factoryPid, update, propagate);
Pierre De Ropef94c882010-04-17 18:23:35 +0000303 }
304
305 /**
Pierre De Rop3e100372010-05-24 12:43:44 +0000306 * Creates a new Managed Service Factory Configuration Adapter with meta type support. For each new Config Admin
307 * factory configuration matching the factoryPid, an adapter will be created based on the adapter implementation
308 * class. The adapter will be registered with the specified interface, and with the specified adapter service
309 * properties. Depending on the <code>propagate</code> parameter, every public factory configuration properties
Pierre De Ropef94c882010-04-17 18:23:35 +0000310 * (which don't start with ".") will be propagated along with the adapter service properties.
311 * It will also inherit all dependencies.
312 *
Pierre De Ropc3dfbb72010-05-24 13:16:35 +0000313 * <h3>Usage Example</h3>
314 *
315 * <blockquote><pre>
316 * PropertyMetaData[] propertiesMetaData = new PropertyMetaData[] {
317 * manager.createPropertyMetaData()
318 * .setCardinality(Integer.MAX_VALUE)
319 * .setType(String.class)
320 * .setHeading("English words")
321 * .setDescription("Declare here some valid english words")
322 * .setDefaults(new String[] {"hello", "world"})
323 * .setId("words")
324 * };
325 *
326 * manager.add(createFactoryConfigurationAdapterService("FactoryPid",
327 * "updated",
328 * true, // propagate CM settings
329 * "EnglishDictionary",
330 * "English dictionary configuration properties",
331 * null,
332 * propertiesMetaData)
333 * .setImplementation(Adapter.class));
334 * </pre></blockquote>
335 *
Pierre De Ropef94c882010-04-17 18:23:35 +0000336 * @param factoryPid the pid matching the factory configuration
337 * @param update the adapter method name that will be notified when the factory configuration is created/updated.
Pierre De Ropef94c882010-04-17 18:23:35 +0000338 * @param propagate true if public factory configuration should be propagated to the adapter service properties
Pierre De Rop3e100372010-05-24 12:43:44 +0000339 * @param heading The label used to display the tab name (or section) where the properties are displayed.
340 * Example: "Printer Service"
341 * @param desc A human readable description of the factory PID this configuration is associated with.
342 * Example: "Configuration for the PrinterService bundle"
Pierre De Rop9a8ebfd2010-04-25 22:25:34 +0000343 * @param localization Points to the basename of the Properties file that can localize the Meta Type informations.
344 * The default localization base name for the properties is OSGI-INF/l10n/bundle, but can
Pierre De Rop3e100372010-05-24 12:43:44 +0000345 * be overridden by the manifest Bundle-Localization header (see core specification, in section Localization
346 * on page 68). You can specify a specific localization basename file using this parameter
347 * (e.g. <code>"person"</code> will match person_du_NL.properties in the root bundle directory).
Pierre De Rop9a8ebfd2010-04-25 22:25:34 +0000348 * @param propertiesMetaData Array of MetaData regarding configuration properties
349 * @return a service that acts as a factory for generating the managed service factory configuration adapter
350 */
Pierre De Rop3e100372010-05-24 12:43:44 +0000351 public Service createFactoryConfigurationAdapterService(String factoryPid, String update, boolean propagate,
352 String heading, String desc, String localization,
353 PropertyMetaData[] propertiesMetaData)
Pierre De Rop9a8ebfd2010-04-25 22:25:34 +0000354 {
Pierre De Rop3e100372010-05-24 12:43:44 +0000355 return new FactoryConfigurationAdapterServiceImpl(this, factoryPid, update, propagate, m_context, m_logger,
356 heading, desc, localization, propertiesMetaData);
Pierre De Rop9a8ebfd2010-04-25 22:25:34 +0000357 }
358
359 /**
Marcel Offermansa962bc92009-11-21 17:59:33 +0000360 * Returns a list of services.
361 *
362 * @return a list of services
363 */
364 public List getServices() {
365 return Collections.unmodifiableList(m_services);
366 }
Marcel Offermansa962bc92009-11-21 17:59:33 +0000367}