blob: 398524f2cb8c91ee3a3fa9c8344bea2ad8f8cd14 [file] [log] [blame]
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001/*
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002 * 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 */
19package org.apache.felix.cm.impl;
20
21
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000022import java.io.IOException;
23import java.security.SecureRandom;
Felix Meschberger4f269292011-10-21 13:52:31 +000024import java.text.MessageFormat;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000025import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.Dictionary;
28import java.util.Enumeration;
29import java.util.HashMap;
30import java.util.Hashtable;
31import java.util.Iterator;
32import java.util.List;
33import java.util.Map;
34import java.util.Random;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000035
36import org.apache.felix.cm.PersistenceManager;
37import org.apache.felix.cm.file.FilePersistenceManager;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000038import org.apache.felix.cm.impl.helper.BaseTracker;
39import org.apache.felix.cm.impl.helper.ManagedServiceFactoryTracker;
40import org.apache.felix.cm.impl.helper.ManagedServiceTracker;
41import org.apache.felix.cm.impl.helper.TargetedPID;
42import org.osgi.framework.Bundle;
43import org.osgi.framework.BundleActivator;
44import org.osgi.framework.BundleContext;
45import org.osgi.framework.BundleEvent;
46import org.osgi.framework.BundleListener;
47import org.osgi.framework.Constants;
48import org.osgi.framework.Filter;
49import org.osgi.framework.InvalidSyntaxException;
50import org.osgi.framework.ServiceReference;
51import org.osgi.framework.ServiceRegistration;
52import org.osgi.service.cm.ConfigurationAdmin;
53import org.osgi.service.cm.ConfigurationEvent;
54import org.osgi.service.cm.ConfigurationException;
55import org.osgi.service.cm.ConfigurationListener;
56import org.osgi.service.cm.ConfigurationPermission;
57import org.osgi.service.cm.ConfigurationPlugin;
58import org.osgi.service.cm.ManagedService;
59import org.osgi.service.cm.ManagedServiceFactory;
60import org.osgi.service.cm.SynchronousConfigurationListener;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000061import org.osgi.service.log.LogService;
62import org.osgi.util.tracker.ServiceTracker;
63
64
65/**
66 * The <code>ConfigurationManager</code> is the central class in this
67 * implementation of the Configuration Admin Service Specification. As such it
68 * has the following tasks:
69 * <ul>
70 * <li>It is a <code>BundleActivator</code> which is called when the bundle
71 * is started and stopped.
72 * <li>It is a <code>BundleListener</code> which gets informed when the
73 * states of bundles change. Mostly this is needed to unbind any bound
74 * configuration in case a bundle is uninstalled.
75 * <li>It is a <code>ServiceListener</code> which gets informed when
76 * <code>ManagedService</code> and <code>ManagedServiceFactory</code>
77 * services are registered and unregistered. This is used to provide
78 * configuration to these services. As a service listener it also listens for
79 * {@link PersistenceManager} instances being registered to support different
80 * configuration persistence layers.
81 * <li>A {@link ConfigurationAdminFactory} instance is registered as the
82 * <code>ConfigurationAdmin</code> service.
83 * <li>A {@link FilePersistenceManager} instance is registered as a default
84 * {@link PersistenceManager}.
85 * <li>Last but not least this instance manages all tasks laid out in the
86 * specification such as maintaining configuration, taking care of configuration
87 * events, etc.
88 * </ul>
89 * <p>
90 * The default {@link FilePersistenceManager} is configured with a configuration
91 * location taken from the <code>felix.cm.dir</code> framework property. If
92 * this property is not set the <code>config</code> directory in the current
93 * working directory as specified in the <code>user.dir</code> system property
94 * is used.
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000095 */
96public class ConfigurationManager implements BundleActivator, BundleListener
97{
98
99 /**
100 * The name of the bundle context property defining the location for the
101 * configuration files (value is "felix.cm.dir").
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000102 *
Carsten Ziegeler7853b9a2008-01-11 16:30:24 +0000103 * @see #start(BundleContext)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000104 */
105 public static final String CM_CONFIG_DIR = "felix.cm.dir";
106
Felix Meschberger08282c32009-01-28 07:01:55 +0000107 /**
108 * The name of the bundle context property defining the maximum log level
109 * (value is "felix.cm.loglevel"). The log level setting is only used if
110 * there is no OSGi LogService available. Otherwise this setting is ignored.
111 * <p>
112 * This value of this property is expected to be an integer number
113 * corresponding to the log level values of the OSGi LogService. That is 1
114 * for errors, 2 for warnings, 3 for informational messages and 4 for debug
115 * messages. The default value is 2, such that only warnings and errors are
116 * logged in the absence of a LogService.
117 */
118 public static final String CM_LOG_LEVEL = "felix.cm.loglevel";
119
Felix Meschberger85b355d2007-08-31 07:17:38 +0000120 // The name of the LogService (not using the class, which might be missing)
121 private static final String LOG_SERVICE_NAME = "org.osgi.service.log.LogService";
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000122
Felix Meschberger08282c32009-01-28 07:01:55 +0000123 private static final int CM_LOG_LEVEL_DEFAULT = 2;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000124
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000125 // random number generator to create configuration PIDs for factory
126 // configurations
Felix Meschberger417f66c2011-02-04 11:25:23 +0000127 private static Random numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000128
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000129 // the BundleContext of the Configuration Admin Service bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000130 BundleContext bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000131
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000132 // the service registration of the configuration admin
Felix Meschberger4b26df92011-02-01 12:41:45 +0000133 private volatile ServiceRegistration configurationAdminRegistration;
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000134
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000135 // the ServiceTracker to emit log services (see log(int, String, Throwable))
136 private ServiceTracker logTracker;
137
138 // the ConfigurationEvent listeners
139 private ServiceTracker configurationListenerTracker;
140
141 // service tracker for managed services
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000142 private ManagedServiceTracker managedServiceTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000143
144 // service tracker for managed service factories
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000145 private ManagedServiceFactoryTracker managedServiceFactoryTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000146
147 // PersistenceManager services
148 private ServiceTracker persistenceManagerTracker;
149
150 // the thread used to schedule tasks required to run asynchronously
151 private UpdateThread updateThread;
152
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000153 // the thread used to schedule events to be dispatched asynchronously
154 private UpdateThread eventThread;
155
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000156 /**
157 * The actual list of {@link PersistenceManager persistence managers} to use
158 * when looking for configuration data. This list is built from the
159 * {@link #persistenceManagerMap}, which is ordered according to the
160 * {@link RankingComparator}.
161 */
162 private PersistenceManager[] persistenceManagers;
163
164 // the persistenceManagerTracker.getTrackingCount when the
165 // persistenceManagers were last got
166 private int pmtCount;
167
168 // the cache of Factory instances mapped by their factory PID
Felix Meschberger6a698df2009-08-16 18:38:46 +0000169 private final Map factories = new HashMap();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000170
171 // the cache of Configuration instances mapped by their PID
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000172 // have this always set to prevent NPE on bundle shutdown
173 private final Map configurations = new HashMap();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000174
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000175 /**
176 * The map of dynamic configuration bindings. This maps the
177 * PID of the dynamically bound configuration or factory to its bundle
178 * location.
179 * <p>
180 * On bundle startup this map is loaded from persistence and validated
181 * against the locations of installed bundles: Entries pointing to bundle
182 * locations not currently installed are removed.
183 * <p>
184 * The map is written to persistence on each change.
185 */
186 private DynamicBindings dynamicBindings;
187
Felix Meschberger08282c32009-01-28 07:01:55 +0000188 // the maximum log level when no LogService is available
189 private int logLevel = CM_LOG_LEVEL_DEFAULT;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000190
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000191 // flag indicating whether BundleChange events should be consumed (FELIX-979)
192 private volatile boolean handleBundleEvents;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000193
Felix Meschberger623f7142012-01-31 07:13:37 +0000194 // flag indicating whether the manager is considered alive
195 private volatile boolean isActive;
196
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000197 public void start( BundleContext bundleContext )
198 {
199 // track the log service using a ServiceTracker
Felix Meschberger85b355d2007-08-31 07:17:38 +0000200 logTracker = new ServiceTracker( bundleContext, LOG_SERVICE_NAME , null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000201 logTracker.open();
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000202
Felix Meschberger08282c32009-01-28 07:01:55 +0000203 // assign the log level
204 String logLevelProp = bundleContext.getProperty( CM_LOG_LEVEL );
205 if ( logLevelProp == null )
206 {
207 logLevel = CM_LOG_LEVEL_DEFAULT;
208 }
209 else
210 {
211 try
212 {
213 logLevel = Integer.parseInt( logLevelProp );
214 }
215 catch ( NumberFormatException nfe )
216 {
217 logLevel = CM_LOG_LEVEL_DEFAULT;
218 }
219 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000220
221 // set up some fields
222 this.bundleContext = bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000223
224 // configurationlistener support
225 configurationListenerTracker = new ServiceTracker( bundleContext, ConfigurationListener.class.getName(), null );
226 configurationListenerTracker.open();
227
228 // initialize the asynchonous updater thread
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000229 ThreadGroup tg = new ThreadGroup( "Configuration Admin Service" );
230 tg.setDaemon( true );
231 this.updateThread = new UpdateThread( this, tg, "CM Configuration Updater" );
232 this.eventThread = new UpdateThread( this, tg, "CM Event Dispatcher" );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000233
234 // set up the location (might throw IllegalArgumentException)
235 try
236 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000237 FilePersistenceManager fpm = new FilePersistenceManager( bundleContext, bundleContext
238 .getProperty( CM_CONFIG_DIR ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000239 Hashtable props = new Hashtable();
240 props.put( Constants.SERVICE_PID, fpm.getClass().getName() );
241 props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
242 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
243 props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
244 bundleContext.registerService( PersistenceManager.class.getName(), fpm, props );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000245
246 // setup dynamic configuration bindings
247 dynamicBindings = new DynamicBindings( bundleContext, fpm );
248 }
249 catch ( IOException ioe )
250 {
251 log( LogService.LOG_ERROR, "Failure setting up dynamic configuration bindings", ioe );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000252 }
253 catch ( IllegalArgumentException iae )
254 {
255 log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
256 }
257
258 // register as bundle and service listener
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000259 handleBundleEvents = true;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000260 bundleContext.addBundleListener( this );
261
262 // get all persistence managers to begin with
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000263 pmtCount = 1; // make sure to get the persistence managers at least once
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000264 persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
265 persistenceManagerTracker.open();
266
Felix Meschberger623f7142012-01-31 07:13:37 +0000267 // consider alive now (before clients use Configuration Admin
268 // service registered in the next step)
269 isActive = true;
270
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000271 // create and register configuration admin - start after PM tracker ...
272 ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
273 Hashtable props = new Hashtable();
274 props.put( Constants.SERVICE_PID, "org.apache.felix.cm.ConfigurationAdmin" );
275 props.put( Constants.SERVICE_DESCRIPTION, "Configuration Admin Service Specification 1.2 Implementation" );
276 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000277 configurationAdminRegistration = bundleContext.registerService( ConfigurationAdmin.class.getName(), caf, props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000278
Felix Meschberger4b26df92011-02-01 12:41:45 +0000279 // start processing the event queues only after registering the service
280 // see FELIX-2813 for details
281 this.updateThread.start();
282 this.eventThread.start();
283
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000284 // start handling ManagedService[Factory] services
Carsten Ziegeler41683982007-12-27 08:35:27 +0000285 managedServiceTracker = new ManagedServiceTracker(this);
286 managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this);
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000287 }
288
289
290 public void stop( BundleContext bundleContext )
291 {
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000292
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000293 // stop handling bundle events immediately
294 handleBundleEvents = false;
295
Felix Meschberger4b26df92011-02-01 12:41:45 +0000296 // stop queue processing before unregistering the service
297 // see FELIX-2813 for details
298 if ( updateThread != null )
299 {
300 updateThread.terminate();
301 }
302 if ( eventThread != null )
303 {
304 eventThread.terminate();
305 }
306
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000307 // immediately unregister the Configuration Admin before cleaning up
Felix Meschberger10568352009-01-15 08:57:11 +0000308 // clearing the field before actually unregistering the service
309 // prevents IllegalStateException in getServiceReference() if
310 // the field is not null but the service already unregistered
311 if (configurationAdminRegistration != null) {
312 ServiceRegistration reg = configurationAdminRegistration;
313 configurationAdminRegistration = null;
314 reg.unregister();
315 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000316
Felix Meschberger623f7142012-01-31 07:13:37 +0000317 // consider inactive after unregistering such that during
318 // unregistration the manager is still alive and can react
319 isActive = false;
320
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000321 // stop handling ManagedService[Factory] services
322 managedServiceFactoryTracker.close();
323 managedServiceTracker.close();
324
325 // don't care for PersistenceManagers any more
326 persistenceManagerTracker.close();
327
328 // stop listening for events
329 bundleContext.removeBundleListener( this );
330
331 if ( configurationListenerTracker != null )
332 {
333 configurationListenerTracker.close();
334 }
335
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000336 if ( logTracker != null )
337 {
338 logTracker.close();
339 }
340
Felix Meschberger6a698df2009-08-16 18:38:46 +0000341 // just ensure the configuration cache is empty
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000342 synchronized ( configurations )
343 {
344 configurations.clear();
345 }
346
Felix Meschberger6a698df2009-08-16 18:38:46 +0000347 // just ensure the factory cache is empty
348 synchronized ( factories )
349 {
350 factories.clear();
351 }
352
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000353 this.bundleContext = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000354 }
355
356
Felix Meschberger623f7142012-01-31 07:13:37 +0000357 /**
358 * Returns <code>true</code> if this manager is considered active.
359 */
360 boolean isActive()
361 {
362 return isActive;
363 }
364
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000365 public BundleContext getBundleContext()
366 {
367 return bundleContext;
368 }
Felix Meschberger623f7142012-01-31 07:13:37 +0000369
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000370 // ---------- Configuration caching support --------------------------------
371
372 ConfigurationImpl getCachedConfiguration( String pid )
373 {
374 synchronized ( configurations )
375 {
376 return ( ConfigurationImpl ) configurations.get( pid );
377 }
378 }
379
380
Felix Meschberger6a698df2009-08-16 18:38:46 +0000381 ConfigurationImpl[] getCachedConfigurations()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000382 {
383 synchronized ( configurations )
384 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000385 return ( ConfigurationImpl[] ) configurations.values().toArray(
386 new ConfigurationImpl[configurations.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000387 }
388 }
389
390
Felix Meschberger2941ef92007-08-20 13:15:16 +0000391 ConfigurationImpl cacheConfiguration( ConfigurationImpl configuration )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000392 {
393 synchronized ( configurations )
394 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000395 Object existing = configurations.get( configuration.getPid() );
396 if ( existing != null )
397 {
398 return ( ConfigurationImpl ) existing;
399 }
400
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000401 configurations.put( configuration.getPid(), configuration );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000402 return configuration;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000403 }
404 }
405
406
407 void removeConfiguration( ConfigurationImpl configuration )
408 {
409 synchronized ( configurations )
410 {
411 configurations.remove( configuration.getPid() );
412 }
413 }
414
415
Felix Meschberger6a698df2009-08-16 18:38:46 +0000416 Factory getCachedFactory( String factoryPid )
417 {
418 synchronized ( factories )
419 {
420 return ( Factory ) factories.get( factoryPid );
421 }
422 }
423
424
425 Factory[] getCachedFactories()
426 {
427 synchronized ( factories )
428 {
429 return ( Factory[] ) factories.values().toArray( new Factory[factories.size()] );
430 }
431 }
432
433
434 void cacheFactory( Factory factory )
435 {
436 synchronized ( factories )
437 {
438 factories.put( factory.getFactoryPid(), factory );
439 }
440 }
441
442
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000443 // ---------- ConfigurationAdminImpl support
Felix Meschberger6a698df2009-08-16 18:38:46 +0000444
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000445 void setDynamicBundleLocation( final String pid, final String location )
446 {
447 if ( dynamicBindings != null )
448 {
449 try
450 {
451 dynamicBindings.putLocation( pid, location );
452 }
453 catch ( IOException ioe )
454 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000455 log( LogService.LOG_ERROR, "Failed storing dynamic configuration binding for {0} to {1}", new Object[]
456 { pid, location, ioe } );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000457 }
458 }
459 }
460
461
462 String getDynamicBundleLocation( final String pid )
463 {
464 if ( dynamicBindings != null )
465 {
466 return dynamicBindings.getLocation( pid );
467 }
468
469 return null;
470 }
471
472
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000473 ConfigurationImpl createFactoryConfiguration( String factoryPid, String location ) throws IOException
474 {
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000475 return cacheConfiguration( createConfiguration( createPid( factoryPid ), factoryPid, location ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000476 }
477
478
Felix Meschbergerad949872011-11-16 10:34:54 +0000479 /**
480 * Returns the {@link ConfigurationImpl} with the given PID if
481 * available in the internal cache or from any persistence manager.
482 * Otherwise <code>null</code> is returned.
483 *
484 * @param pid The PID for which to return the configuration
485 * @return The configuration or <code>null</code> if non exists
486 * @throws IOException If an error occurrs reading from a persistence
487 * manager.
488 */
489 ConfigurationImpl getConfiguration( String pid ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000490 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000491 ConfigurationImpl config = getCachedConfiguration( pid );
492 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000493 {
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000494 log( LogService.LOG_DEBUG, "Found cached configuration {0} bound to {1}", new Object[]
495 { pid, config.getBundleLocation() } );
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000496
497 config.ensureFactoryConfigPersisted();
498
Felix Meschberger2941ef92007-08-20 13:15:16 +0000499 return config;
500 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000501
Felix Meschberger2941ef92007-08-20 13:15:16 +0000502 PersistenceManager[] pmList = getPersistenceManagers();
503 for ( int i = 0; i < pmList.length; i++ )
504 {
505 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000506 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000507 Dictionary props = pmList[i].load( pid );
508 config = new ConfigurationImpl( this, pmList[i], props );
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000509 log( LogService.LOG_DEBUG, "Found existing configuration {0} bound to {1}", new Object[]
510 { pid, config.getBundleLocation() } );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000511 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000512 }
513 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000514
Felix Meschberger2941ef92007-08-20 13:15:16 +0000515 // neither the cache nor any persistence manager has configuration
516 return null;
517 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000518
519
Felix Meschbergerad949872011-11-16 10:34:54 +0000520 /**
521 * Creates a regular (non-factory) configuration for the given PID
522 * setting the bundle location accordingly.
523 * <p>
524 * This method assumes the configuration to not exist yet and will
525 * create it without further checking.
526 *
527 * @param pid The PID of the new configuration
528 * @param bundleLocation The location to set on the new configuration.
529 * This may be <code>null</code> to not bind the configuration
530 * yet.
531 * @return The new configuration persisted in the first persistence
532 * manager.
533 * @throws IOException If an error occurrs writing the configuration
534 * to the persistence.
535 */
536 ConfigurationImpl createConfiguration( String pid, String bundleLocation ) throws IOException
Felix Meschberger2941ef92007-08-20 13:15:16 +0000537 {
538 // check for existing (cached or persistent) configuration
Felix Meschbergerad949872011-11-16 10:34:54 +0000539 ConfigurationImpl config = getConfiguration( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000540 if ( config != null )
541 {
542 return config;
543 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000544
Felix Meschberger2941ef92007-08-20 13:15:16 +0000545 // else create new configuration also setting the bundle location
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000546 // and cache the new configuration
547 config = createConfiguration( pid, null, bundleLocation );
548 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000549 }
550
551
552 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
553 throws IOException, InvalidSyntaxException
554 {
555 Filter filter = null;
556 if ( filterString != null )
557 {
558 filter = bundleContext.createFilter( filterString );
559 }
560
Felix Meschberger4f269292011-10-21 13:52:31 +0000561 log( LogService.LOG_DEBUG, "Listing configurations matching {0}", new Object[]
562 { filterString } );
563
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000564 List configList = new ArrayList();
565
566 PersistenceManager[] pmList = getPersistenceManagers();
567 for ( int i = 0; i < pmList.length; i++ )
568 {
569 Enumeration configs = pmList[i].getDictionaries();
570 while ( configs.hasMoreElements() )
571 {
572 Dictionary config = ( Dictionary ) configs.nextElement();
573
574 // ignore non-Configuration dictionaries
Felix Meschberger86a0d172007-07-04 07:15:01 +0000575 String pid = ( String ) config.get( Constants.SERVICE_PID );
576 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000577 {
578 continue;
579 }
580
Felix Meschberger007c50e2011-10-20 12:39:38 +0000581 // CM 1.4 / 104.13.2.3 Permission required
582 if ( !configurationAdmin.hasPermission( ( String ) config
583 .get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000584 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000585 log(
586 LogService.LOG_DEBUG,
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000587 "Omitting configuration {0}: No permission for bundle {1} on configuration bound to {2}",
Felix Meschberger4f269292011-10-21 13:52:31 +0000588 new Object[]
589 { config.get( Constants.SERVICE_PID ), configurationAdmin.getBundle().getLocation(),
590 config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000591 continue;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000592 }
593
594 // check filter
595 if ( filter == null || filter.match( config ) )
596 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000597 // ensure the service.pid and returned a cached config if available
598 ConfigurationImpl cfg = getCachedConfiguration( pid );
599 if ( cfg == null )
600 {
601 cfg = new ConfigurationImpl( this, pmList[i], config );
602 }
603
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000604 // FELIX-611: Ignore configuration objects without props
605 if ( !cfg.isNew() )
606 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000607 log( LogService.LOG_DEBUG, "Adding configuration {0}", new Object[]
608 { config.get( Constants.SERVICE_PID ) } );
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000609 configList.add( cfg );
610 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000611 else
612 {
613 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Is new", new Object[]
614 { config.get( Constants.SERVICE_PID ) } );
615 }
616 } else {
617 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Does not match filter", new Object[]
618 { config.get( Constants.SERVICE_PID ) } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000619 }
620 }
621 }
622
Felix Meschberger8faceff2007-07-04 07:19:48 +0000623 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000624 .size()] );
625 }
626
627
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000628 void deleted( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000629 {
630 // remove the configuration from the cache
631 removeConfiguration( config );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000632 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, config.getPid(), config.getFactoryPid() );
633 updateThread.schedule( new DeleteConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000634 log( LogService.LOG_DEBUG, "DeleteConfiguration({0}) scheduled", new Object[]
635 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000636 }
637
638
Felix Meschbergerce67d732009-08-20 06:26:35 +0000639 void updated( ConfigurationImpl config, boolean fireEvent )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000640 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000641 if ( fireEvent )
642 {
643 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPid(), config.getFactoryPid() );
644 }
645 updateThread.schedule( new UpdateConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000646 log( LogService.LOG_DEBUG, "UpdateConfiguration({0}) scheduled", new Object[]
647 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000648 }
649
650
Felix Meschberger007c50e2011-10-20 12:39:38 +0000651 void locationChanged( ConfigurationImpl config, String oldLocation )
652 {
653 fireConfigurationEvent( ConfigurationEvent.CM_LOCATION_CHANGED, config.getPid(), config.getFactoryPid() );
Felix Meschberger35658d52011-10-20 21:43:58 +0000654 if ( oldLocation != null && !config.isNew() )
Felix Meschberger007c50e2011-10-20 12:39:38 +0000655 {
656 updateThread.schedule( new LocationChanged( config, oldLocation ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000657 log( LogService.LOG_DEBUG, "LocationChanged({0}, {1}=>{2}) scheduled", new Object[]
658 { config.getPid(), oldLocation, config.getBundleLocation() } );
Felix Meschberger35658d52011-10-20 21:43:58 +0000659 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000660 else
Felix Meschberger35658d52011-10-20 21:43:58 +0000661 {
662 log( LogService.LOG_DEBUG,
Felix Meschberger4f269292011-10-21 13:52:31 +0000663 "LocationChanged not scheduled for {0} (old location is null or configuration is new)", new Object[]
664 { config.getPid() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000665 }
666 }
667
668
Felix Meschberger66423332007-08-22 08:46:34 +0000669 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000670 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000671 FireConfigurationEvent event = new FireConfigurationEvent( type, pid, factoryPid );
Felix Meschberger0770cad2012-06-11 12:36:52 +0000672 event.fireSynchronousEvents();
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000673 if ( event.hasConfigurationEventListeners() )
674 {
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000675 eventThread.schedule( event );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000676 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000677 else
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000678 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000679 log( LogService.LOG_DEBUG, "No ConfigurationListeners to send {0} event to.", new Object[]
680 { event.getTypeName() } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000681 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000682 }
683
684
685 // ---------- BundleListener -----------------------------------------------
686
687 public void bundleChanged( BundleEvent event )
688 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000689 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000690 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000691 final String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000692
Felix Meschberger6a698df2009-08-16 18:38:46 +0000693 // we only reset dynamic bindings, which are only present in
694 // cached configurations, hence only consider cached configs here
695 final ConfigurationImpl[] configs = getCachedConfigurations();
696 for ( int i = 0; i < configs.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000697 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000698 final ConfigurationImpl cfg = configs[i];
Felix Meschberger41cce522009-08-19 05:54:40 +0000699 if ( location.equals( cfg.getDynamicBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000700 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000701 cfg.setDynamicBundleLocation( null, true );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000702 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000703 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000704 }
705 }
706
707
708 // ---------- internal -----------------------------------------------------
709
710 private PersistenceManager[] getPersistenceManagers()
711 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000712 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
713 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000714 {
715
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000716 List pmList = new ArrayList();
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000717 PersistenceManager[] pm;
718
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000719 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
720 if ( refs == null || refs.length == 0 )
721 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000722 pm = new PersistenceManager[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000723 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000724 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000725 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000726 // sort the references according to the cmRanking property
Felix Meschberger007c50e2011-10-20 12:39:38 +0000727 if ( refs.length > 1 )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000728 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000729 Arrays.sort( refs, RankingComparator.SRV_RANKING );
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000730 }
731
732 // create the service array from the sorted set of referenecs
Felix Meschberger007c50e2011-10-20 12:39:38 +0000733 for ( int i = 0; i < refs.length; i++ )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000734 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000735 Object service = persistenceManagerTracker.getService( refs[i] );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000736 if ( service != null )
737 {
Felix Meschbergera86cdfc2010-08-25 09:32:36 +0000738 pmList.add( new CachingPersistenceManagerProxy( ( PersistenceManager ) service ) );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000739 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000740 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000741
742 pm = ( PersistenceManager[] ) pmList.toArray( new PersistenceManager[pmList.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000743 }
744
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000745 pmtCount = pm.length;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000746 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000747 }
748
749 return persistenceManagers;
750 }
751
752
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000753 private ServiceReference getServiceReference()
754 {
755 ServiceRegistration reg = configurationAdminRegistration;
Felix Meschberger0770cad2012-06-11 12:36:52 +0000756 if (reg != null) {
757 return reg.getReference();
758 }
759
760 // probably called for firing an event during service registration
761 // since we didn't get the service registration yet we use the
762 // service registry to get our service reference
763 BundleContext context = bundleContext;
764 if ( context != null )
765 {
766 try
767 {
768 ServiceReference[] refs = context.getServiceReferences( ConfigurationAdmin.class.getName(), null );
769 if ( refs != null )
770 {
771 for ( int i = 0; i < refs.length; i++ )
772 {
773 if ( refs[i].getBundle().getBundleId() == context.getBundle().getBundleId() )
774 {
775 return refs[i];
776 }
777 }
778 }
779 }
780 catch ( InvalidSyntaxException e )
781 {
782 // unexpected since there is no filter
783 }
784 }
785
786 // service references
787 return null;
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000788 }
789
790
Felix Meschberger05d89e12011-11-03 23:37:10 +0000791 /**
792 * Configures the ManagedService and returns the service.pid
793 * service property as a String[], which may be <code>null</code> if
794 * the ManagedService does not have such a property.
795 */
Felix Meschberger05d89e12011-11-03 23:37:10 +0000796 /**
797 * Configures the ManagedServiceFactory and returns the service.pid
798 * service property as a String[], which may be <code>null</code> if
799 * the ManagedServiceFactory does not have such a property.
800 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000801 //TODO: replace above configure methods
802 public void configure( String pid, ServiceReference sr, Object service, final boolean factory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000803 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000804 Runnable r;
805 if ( factory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000806 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000807 r = new ManagedServiceFactoryUpdate( pid, sr, ( ManagedServiceFactory ) service );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000808 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000809 else
810 {
811 r = new ManagedServiceUpdate( pid, sr, ( ManagedService ) service );
812 }
813 updateThread.schedule( r );
814 log( LogService.LOG_DEBUG, "[{0}] scheduled", new Object[]
815 { r } );
Felix Meschberger851c6412009-08-16 18:43:26 +0000816 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000817
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000818
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000819 /**
820 * Factory method to create a new configuration object. The configuration
821 * object returned is not stored in configuration cache and only persisted
822 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000823 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000824 * @param pid
825 * The PID of the new configuration object. Must not be
826 * <code>null</code>.
827 * @param factoryPid
828 * The factory PID of the new configuration. Not
Felix Meschberger6a698df2009-08-16 18:38:46 +0000829 * <code>null</code> if the new configuration object belongs to a
830 * factory. The configuration object will not be persisted if
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000831 * this parameter is not <code>null</code>.
832 * @param bundleLocation
833 * The bundle location of the bundle to which the configuration
Felix Meschberger6a698df2009-08-16 18:38:46 +0000834 * belongs or <code>null</code> if the configuration is not bound
835 * yet.
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000836 * @return The new configuration object
837 * @throws IOException
838 * May be thrown if an error occurrs persisting the new
839 * configuration object.
840 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000841 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000842 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000843 log( LogService.LOG_DEBUG, "createConfiguration({0}, {1}, {2})", new Object[]
844 { pid, factoryPid, bundleLocation } );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000845 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000846 }
847
848
849 Factory getFactory( String factoryPid ) throws IOException
850 {
Felix Meschbergerf4631322008-03-10 12:32:35 +0000851 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000852 if ( factory != null )
853 {
854 return factory;
855 }
856
857 PersistenceManager[] pmList = getPersistenceManagers();
858 for ( int i = 0; i < pmList.length; i++ )
859 {
860 if ( Factory.exists( pmList[i], factoryPid ) )
861 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000862 factory = Factory.load( this, pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000863 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000864 return factory;
865 }
866 }
867
868 // if getting here, there is no configuration yet, optionally create new
869 return createFactory( factoryPid );
870 }
871
872
873 Factory createFactory( String factoryPid )
874 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000875 Factory factory = new Factory( this, getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000876 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000877 return factory;
878 }
879
880
Felix Meschberger2941ef92007-08-20 13:15:16 +0000881 /**
882 * Calls the registered configuration plugins on the given configuration
Felix Meschberger41cce522009-08-19 05:54:40 +0000883 * properties from the given configuration object unless the configuration
884 * has just been created and not been updated yet.
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000885 *
Felix Meschberger41cce522009-08-19 05:54:40 +0000886 * @param props The configuraiton properties run through the registered
887 * ConfigurationPlugin services. This may be <code>null</code>
888 * in which case this method just immediately returns.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000889 * @param targetPid The identification of the configuration update used to
890 * select the plugins according to their cm.target service
891 * property
Felix Meschberger2941ef92007-08-20 13:15:16 +0000892 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000893 * is to be updated with configuration
Felix Meschberger2941ef92007-08-20 13:15:16 +0000894 * @param cfg The configuration object whose properties have to be passed
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000895 * through the plugins
Felix Meschberger2941ef92007-08-20 13:15:16 +0000896 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000897 public void callPlugins( final Dictionary props, final String targetPid, final ServiceReference sr,
Felix Meschberger41cce522009-08-19 05:54:40 +0000898 final ConfigurationImpl cfg )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000899 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000900 // guard against NPE for new configuration never updated
901 if (props == null) {
Felix Meschberger41cce522009-08-19 05:54:40 +0000902 return;
Felix Meschberger2941ef92007-08-20 13:15:16 +0000903 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000904
905 ServiceReference[] plugins = null;
906 try
907 {
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000908 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000909 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000910 }
911 catch ( InvalidSyntaxException ise )
912 {
913 // no filter, no exception ...
914 }
915
916 // abort early if there are no plugins
917 if ( plugins == null || plugins.length == 0 )
918 {
Felix Meschberger41cce522009-08-19 05:54:40 +0000919 return;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000920 }
921
922 // sort the plugins by their service.cmRanking
Felix Meschberger007c50e2011-10-20 12:39:38 +0000923 if ( plugins.length > 1 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000924 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000925 Arrays.sort( plugins, RankingComparator.CM_RANKING );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000926 }
927
928 // call the plugins in order
Felix Meschberger007c50e2011-10-20 12:39:38 +0000929 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000930 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000931 ServiceReference pluginRef = plugins[i];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000932 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000933 if ( plugin != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000934 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000935 try
936 {
937 plugin.modifyConfiguration( sr, props );
938 }
939 catch ( Throwable t )
940 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000941 log( LogService.LOG_ERROR, "Unexpected problem calling configuration plugin {0}", new Object[]
942 { toString( pluginRef ), t } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000943 }
944 finally
945 {
946 // ensure ungetting the plugin
947 bundleContext.ungetService( pluginRef );
948 }
949 cfg.setAutoProperties( props, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000950 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000951 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000952 }
953
954
955 /**
956 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000957 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000958 * @param factoryPid
959 * @return
960 */
961 private static String createPid( String factoryPid )
962 {
Felix Meschberger417f66c2011-02-04 11:25:23 +0000963 Random ng = numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000964 if ( ng == null )
965 {
Felix Meschberger417f66c2011-02-04 11:25:23 +0000966 // FELIX-2771 Secure Random not available on Mika
967 try
968 {
969 ng = new SecureRandom();
970 }
971 catch ( Throwable t )
972 {
973 // fall back to Random
974 ng = new Random();
975 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000976 }
977
978 byte[] randomBytes = new byte[16];
979 ng.nextBytes( randomBytes );
980 randomBytes[6] &= 0x0f; /* clear version */
981 randomBytes[6] |= 0x40; /* set to version 4 */
982 randomBytes[8] &= 0x3f; /* clear variant */
983 randomBytes[8] |= 0x80; /* set to IETF variant */
984
985 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
986
987 // prefix the new pid with the factory pid
988 buf.append( factoryPid ).append( "." );
989
990 // serialize the UUID into the buffer
991 for ( int i = 0; i < randomBytes.length; i++ )
992 {
993
994 if ( i == 4 || i == 6 || i == 8 || i == 10 )
995 {
996 buf.append( '-' );
997 }
998
999 int val = randomBytes[i] & 0xff;
1000 buf.append( Integer.toHexString( val >> 4 ) );
1001 buf.append( Integer.toHexString( val & 0xf ) );
1002 }
1003
1004 return buf.toString();
1005 }
1006
1007
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001008 public boolean isLogEnabled( int level )
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001009 {
1010 return level <= logLevel;
1011 }
1012
1013
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001014 public void log( int level, String format, Object[] args )
Felix Meschberger4f269292011-10-21 13:52:31 +00001015 {
1016 if ( isLogEnabled( level ) )
1017 {
1018 Throwable throwable = null;
1019 String message = format;
1020
1021 if ( args != null && args.length > 0 )
1022 {
1023 if ( args[args.length - 1] instanceof Throwable )
1024 {
1025 throwable = ( Throwable ) args[args.length - 1];
1026 }
1027 message = MessageFormat.format( format, args );
1028 }
1029
1030 log( level, message, throwable );
1031 }
1032 }
1033
1034
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001035 public void log( int level, String message, Throwable t )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001036 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001037 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +00001038 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001039 if ( log != null )
1040 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +00001041 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001042 return;
1043 }
1044
Felix Meschberger08282c32009-01-28 07:01:55 +00001045 // Otherwise only log if more serious than the configured level
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001046 if ( isLogEnabled( level ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001047 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001048 String code;
1049 switch ( level )
1050 {
1051 case LogService.LOG_INFO:
1052 code = "*INFO *";
1053 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001054
Felix Meschberger08282c32009-01-28 07:01:55 +00001055 case LogService.LOG_WARNING:
1056 code = "*WARN *";
1057 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001058
Felix Meschberger08282c32009-01-28 07:01:55 +00001059 case LogService.LOG_ERROR:
1060 code = "*ERROR*";
1061 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001062
Felix Meschberger08282c32009-01-28 07:01:55 +00001063 case LogService.LOG_DEBUG:
1064 default:
1065 code = "*DEBUG*";
1066 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001067
Felix Meschberger08282c32009-01-28 07:01:55 +00001068 System.err.println( code + " " + message );
1069 if ( t != null )
1070 {
1071 t.printStackTrace( System.err );
1072 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001073 }
1074 }
1075
Felix Meschberger851c6412009-08-16 18:43:26 +00001076
Felix Meschberger851c6412009-08-16 18:43:26 +00001077
Felix Meschberger41cce522009-08-19 05:54:40 +00001078
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001079 public static String toString( ServiceReference ref )
Felix Meschberger41cce522009-08-19 05:54:40 +00001080 {
1081 String[] ocs = ( String[] ) ref.getProperty( "objectClass" );
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001082 StringBuffer buf = new StringBuffer("[");
Felix Meschberger41cce522009-08-19 05:54:40 +00001083 for ( int i = 0; i < ocs.length; i++ )
1084 {
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001085 buf.append(ocs[i]);
Felix Meschberger41cce522009-08-19 05:54:40 +00001086 if ( i < ocs.length - 1 )
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001087 buf.append(", ");
Felix Meschberger41cce522009-08-19 05:54:40 +00001088 }
1089
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001090 buf.append( ", id=" ).append( ref.getProperty( Constants.SERVICE_ID ) );
1091
1092 Bundle provider = ref.getBundle();
1093 if ( provider != null )
1094 {
1095 buf.append( ", bundle=" ).append( provider.getBundleId() );
Felix Meschberger0135b322011-11-16 12:30:22 +00001096 buf.append( '/' ).append( provider.getLocation() );
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001097 }
1098 else
1099 {
1100 buf.append( ", unregistered" );
1101 }
1102
1103 buf.append( "]" );
1104 return buf.toString();
Felix Meschberger41cce522009-08-19 05:54:40 +00001105 }
1106
Felix Meschbergerce67d732009-08-20 06:26:35 +00001107
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001108 public void handleCallBackError( final Throwable error, final ServiceReference target, final ConfigurationImpl config )
Felix Meschbergerce67d732009-08-20 06:26:35 +00001109 {
1110 if ( error instanceof ConfigurationException )
1111 {
1112 final ConfigurationException ce = ( ConfigurationException ) error;
1113 if ( ce.getProperty() != null )
1114 {
Felix Meschberger93edd662012-01-31 07:17:46 +00001115 log( LogService.LOG_ERROR, "{0}: Updating property {1} of configuration {2} caused a problem: {3}",
Felix Meschberger4f269292011-10-21 13:52:31 +00001116 new Object[]
Felix Meschberger93edd662012-01-31 07:17:46 +00001117 { toString( target ), ce.getProperty(), config.getPid(), ce.getReason(), ce } );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001118 }
1119 else
1120 {
Felix Meschberger93edd662012-01-31 07:17:46 +00001121 log( LogService.LOG_ERROR, "{0}: Updating configuration {1} caused a problem: {2}", new Object[]
1122 { toString( target ), config.getPid(), ce.getReason(), ce } );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001123 }
1124 }
1125 else
1126 {
1127 {
Felix Meschberger93edd662012-01-31 07:17:46 +00001128 log( LogService.LOG_ERROR, "{0}: Unexpected problem updating configuration {1}", new Object[]
Felix Meschberger4f269292011-10-21 13:52:31 +00001129 { toString( target ), config, error } );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001130 }
1131
1132 }
1133 }
1134
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001135
Felix Meschberger007c50e2011-10-20 12:39:38 +00001136 /**
1137 * Checks whether the bundle is allowed to receive the configuration
1138 * with the given location binding.
1139 * <p>
1140 * This method implements the logic defined CM 1.4 / 104.4.1:
1141 * <ul>
1142 * <li>If the location is <code>null</code> (the configuration is not
1143 * bound yet), assume the bundle is allowed</li>
1144 * <li>If the location is a single location (no leading "?"), require
1145 * the bundle's location to match</li>
1146 * <li>If the location is a multi-location (leading "?"), assume the
1147 * bundle is allowed if there is no security manager. If there is a
1148 * security manager, check whether the bundle has "target" permission
1149 * on this location.</li>
1150 * </ul>
1151 */
1152 boolean canReceive( final Bundle bundle, final String location )
1153 {
1154 if ( location == null )
1155 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001156 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration=(unbound)", new Object[]
Felix Meschberger61207232011-11-17 10:06:45 +00001157 { bundle.getLocation() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001158 return true;
1159 }
1160 else if ( location.startsWith( "?" ) )
1161 {
1162 // multi-location
1163 if ( System.getSecurityManager() != null )
1164 {
Felix Meschberger61207232011-11-17 10:06:45 +00001165 final boolean hasPermission = bundle.hasPermission( new ConfigurationPermission( location,
1166 ConfigurationPermission.TARGET ) );
1167 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2} (SecurityManager check)",
1168 new Object[]
1169 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1170 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001171 }
Felix Meschberger61207232011-11-17 10:06:45 +00001172
1173 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration={1} (no SecurityManager)",
1174 new Object[]
1175 { bundle.getLocation(), location } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001176 return true;
1177 }
1178 else
1179 {
1180 // single location, must match
Felix Meschberger61207232011-11-17 10:06:45 +00001181 final boolean hasPermission = location.equals( bundle.getLocation() );
1182 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2}", new Object[]
1183 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1184 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001185 }
1186 }
1187
Felix Meschberger61207232011-11-17 10:06:45 +00001188
Felix Meschberger007c50e2011-10-20 12:39:38 +00001189 // ---------- inner classes
1190
Felix Meschberger007c50e2011-10-20 12:39:38 +00001191 /**
1192 * The <code>ManagedServiceUpdate</code> updates a freshly registered
1193 * <code>ManagedService</code> with a specific configuration. If a
1194 * ManagedService is registered with multiple PIDs an instance of this
1195 * class is used for each registered PID.
1196 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001197 private class ManagedServiceUpdate implements Runnable
1198 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001199 private final String pid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001200
Felix Meschberger41cce522009-08-19 05:54:40 +00001201 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001202
Felix Meschberger41cce522009-08-19 05:54:40 +00001203 private final ManagedService service;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001204
Felix Meschberger41cce522009-08-19 05:54:40 +00001205 private final ConfigurationImpl config;
1206
1207 private final Dictionary rawProperties;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001208
Felix Meschberger61207232011-11-17 10:06:45 +00001209 private final long revision;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001210
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001211 ManagedServiceUpdate( String pid, ServiceReference sr, ManagedService service )
1212 {
1213 this.pid = pid;
1214 this.sr = sr;
1215 this.service = service;
Felix Meschberger41cce522009-08-19 05:54:40 +00001216
1217 // get or load configuration for the pid
1218 ConfigurationImpl config = null;
1219 Dictionary rawProperties = null;
Felix Meschberger61207232011-11-17 10:06:45 +00001220 long revision = -1;
Felix Meschberger41cce522009-08-19 05:54:40 +00001221 try
1222 {
Felix Meschbergerad949872011-11-16 10:34:54 +00001223 config = getConfiguration( pid );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001224 if ( config != null )
1225 {
1226 synchronized ( config )
1227 {
1228 rawProperties = config.getProperties( true );
Felix Meschberger61207232011-11-17 10:06:45 +00001229 revision = config.getRevision();
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001230 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001231 }
1232 }
1233 catch ( IOException ioe )
1234 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001235 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1236 { pid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001237 }
1238
1239 this.config = config;
1240 this.rawProperties = rawProperties;
Felix Meschberger61207232011-11-17 10:06:45 +00001241 this.revision = revision;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001242 }
1243
1244
1245 public void run()
1246 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001247 Dictionary properties = rawProperties;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001248
1249 // check configuration and call plugins if existing
Felix Meschberger41cce522009-08-19 05:54:40 +00001250 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001251 {
Felix Meschberger61207232011-11-17 10:06:45 +00001252 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1253 { pid, new Long( revision ) } );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001254
Felix Meschberger41243192009-01-14 19:59:58 +00001255 Bundle serviceBundle = sr.getBundle();
1256 if ( serviceBundle == null )
1257 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001258 log( LogService.LOG_INFO,
1259 "Service for PID {0} seems to already have been unregistered, not updating with configuration",
1260 new Object[]
1261 { pid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001262 return;
1263 }
1264
Felix Meschberger27689c12011-11-16 08:52:04 +00001265 if ( canReceive( serviceBundle, config.getBundleLocation() ) )
Felix Meschberger2941ef92007-08-20 13:15:16 +00001266 {
Felix Meschberger27689c12011-11-16 08:52:04 +00001267 // 104.4.2 Dynamic Binding
1268 config.tryBindLocation( serviceBundle.getLocation() );
1269
1270 // prepare the configuration for the service (call plugins)
1271 callPlugins( properties, pid, sr, config );
1272 }
1273 else
1274 {
1275 // CM 1.4 / 104.13.2.2 / 104.5.3
1276 // act as if there is no configuration
1277 log(
1278 LogService.LOG_DEBUG,
1279 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}; calling with null",
Felix Meschberger4f269292011-10-21 13:52:31 +00001280 new Object[]
1281 { pid, ConfigurationManager.toString( sr ), config.getBundleLocation() } );
Felix Meschberger27689c12011-11-16 08:52:04 +00001282
1283 // CM 1.4 / 104.5.3 ManagedService.updated must be
1284 // called with null if configuration is no visible
1285 properties = null;
Felix Meschberger2941ef92007-08-20 13:15:16 +00001286 }
1287
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001288 }
1289 else
1290 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001291 // 104.5.3 ManagedService.updated must be called with null
1292 // if no configuration is available
Felix Meschberger41cce522009-08-19 05:54:40 +00001293 properties = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001294 }
1295
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001296 // update the service with the configuration
1297 try
1298 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001299 service.updated( properties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001300 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001301 catch ( Throwable t )
1302 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001303 handleCallBackError( t, sr, config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001304 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001305 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001306
Felix Meschberger432e3872008-03-07 14:58:57 +00001307 public String toString()
1308 {
1309 return "ManagedService Update: pid=" + pid;
1310 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001311 }
1312
Felix Meschberger007c50e2011-10-20 12:39:38 +00001313 /**
1314 * The <code>ManagedServiceFactoryUpdate</code> updates a freshly
1315 * registered <code>ManagedServiceFactory</code> with a specific
1316 * configuration. If a ManagedServiceFactory is registered with
1317 * multiple PIDs an instance of this class is used for each registered
1318 * PID.
1319 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001320 private class ManagedServiceFactoryUpdate implements Runnable
1321 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001322 private final String factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001323
Felix Meschberger41cce522009-08-19 05:54:40 +00001324 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001325
Felix Meschberger41cce522009-08-19 05:54:40 +00001326 private final ManagedServiceFactory service;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001327
Felix Meschberger41cce522009-08-19 05:54:40 +00001328 private final Map configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001329
Felix Meschberger61207232011-11-17 10:06:45 +00001330 private final Map revisions;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001331
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001332 ManagedServiceFactoryUpdate( String factoryPid, ServiceReference sr, ManagedServiceFactory service )
1333 {
1334 this.factoryPid = factoryPid;
1335 this.sr = sr;
1336 this.service = service;
Felix Meschberger41cce522009-08-19 05:54:40 +00001337
1338 Factory factory = null;
1339 Map configs = null;
Felix Meschberger61207232011-11-17 10:06:45 +00001340 Map revisions = null;
Felix Meschberger41cce522009-08-19 05:54:40 +00001341 try
1342 {
1343 factory = getFactory( factoryPid );
1344 if (factory != null) {
1345 configs = new HashMap();
Felix Meschberger61207232011-11-17 10:06:45 +00001346 revisions = new HashMap();
Felix Meschberger41cce522009-08-19 05:54:40 +00001347 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
1348 {
1349 final String pid = ( String ) pi.next();
1350 ConfigurationImpl cfg;
1351 try
1352 {
Felix Meschbergerad949872011-11-16 10:34:54 +00001353 cfg = getConfiguration( pid );
Felix Meschberger41cce522009-08-19 05:54:40 +00001354 }
1355 catch ( IOException ioe )
1356 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001357 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1358 { pid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001359 continue;
1360 }
1361
1362 // sanity check on the configuration
1363 if ( cfg == null )
1364 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001365 log( LogService.LOG_ERROR, "Configuration {0} referred to by factory {1} does not exist",
1366 new Object[]
1367 { pid, factoryPid } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001368 factory.removePID( pid );
1369 factory.storeSilently();
1370 continue;
1371 }
1372 else if ( cfg.isNew() )
1373 {
1374 // Configuration has just been created but not yet updated
1375 // we currently just ignore it and have the update mechanism
1376 // provide the configuration to the ManagedServiceFactory
1377 // As of FELIX-612 (not storing new factory configurations)
1378 // this should not happen. We keep this for added stability
1379 // but raise the logging level to error.
Felix Meschberger4f269292011-10-21 13:52:31 +00001380 log( LogService.LOG_ERROR, "Ignoring new configuration pid={0}", new Object[]
1381 { pid } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001382 continue;
1383 }
1384 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1385 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001386 log( LogService.LOG_ERROR,
1387 "Configuration {0} referred to by factory {1} seems to belong to factory {2}",
1388 new Object[]
1389 { pid, factoryPid, cfg.getFactoryPid() } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001390 factory.removePID( pid );
1391 factory.storeSilently();
1392 continue;
1393 }
1394
1395 // get the configuration properties for later
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001396 synchronized ( cfg )
1397 {
1398 configs.put( cfg, cfg.getProperties( true ) );
Felix Meschberger61207232011-11-17 10:06:45 +00001399 revisions.put( cfg, new Long( cfg.getRevision() ) );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001400 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001401 }
1402 }
1403 }
1404 catch ( IOException ioe )
1405 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001406 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID {0}", new Object[]
1407 { factoryPid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001408 }
1409
Felix Meschberger41cce522009-08-19 05:54:40 +00001410 this.configs = configs;
Felix Meschberger61207232011-11-17 10:06:45 +00001411 this.revisions = revisions;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001412 }
1413
1414
1415 public void run()
1416 {
Felix Meschberger41243192009-01-14 19:59:58 +00001417 Bundle serviceBundle = sr.getBundle();
1418 if ( serviceBundle == null )
1419 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001420 log(
1421 LogService.LOG_INFO,
1422 "ManagedServiceFactory for factory PID {0} seems to already have been unregistered, not updating with factory",
1423 new Object[]
1424 { factoryPid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001425 return;
1426 }
1427
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001428 if ( configs == null || configs.isEmpty() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001429 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001430 log( LogService.LOG_DEBUG, "No configuration with factory PID {0}; not updating ManagedServiceFactory",
1431 new Object[]
1432 { factoryPid } );
1433 }
1434 else
1435 {
1436 for ( Iterator ci = configs.entrySet().iterator(); ci.hasNext(); )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001437 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001438 final Map.Entry entry = ( Map.Entry ) ci.next();
1439 final ConfigurationImpl cfg = ( ConfigurationImpl ) entry.getKey();
1440 final Dictionary properties = ( Dictionary ) entry.getValue();
1441 final long revision = ( ( Long ) revisions.get( cfg ) ).longValue();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001442
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001443 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1444 { cfg.getPid(), new Long( revision ) } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001445
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001446 // CM 1.4 / 104.13.2.1
1447 if ( !canReceive( serviceBundle, cfg.getBundleLocation() ) )
Felix Meschberger2941ef92007-08-20 13:15:16 +00001448 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001449 log( LogService.LOG_ERROR,
1450 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1451 new Object[]
1452 { cfg.getPid(), ConfigurationManager.toString( sr ), cfg.getBundleLocation() } );
1453 continue;
Felix Meschberger2941ef92007-08-20 13:15:16 +00001454 }
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001455
1456 // 104.4.2 Dynamic Binding
1457 cfg.tryBindLocation( serviceBundle.getLocation() );
1458
1459 // prepare the configuration for the service (call plugins)
1460 // call the plugins with cm.target set to the service's factory PID
1461 // (clarification in Section 104.9.1 of Compendium 4.2)
1462 callPlugins( properties, factoryPid, sr, cfg );
1463
1464 // update the service with the configuration (if non-null)
1465 if ( properties != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001466 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001467 log( LogService.LOG_DEBUG, "{0}: Updating configuration pid={1}", new Object[]
1468 { ConfigurationManager.toString( sr ), cfg.getPid() } );
1469
1470 try
1471 {
1472 service.updated( cfg.getPid(), properties );
1473 }
1474 catch ( Throwable t )
1475 {
1476 handleCallBackError( t, sr, cfg );
1477 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001478 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001479 }
1480 }
1481 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001482
1483
Felix Meschberger432e3872008-03-07 14:58:57 +00001484 public String toString()
1485 {
1486 return "ManagedServiceFactory Update: factoryPid=" + factoryPid;
1487 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001488 }
1489
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001490 private abstract class ConfigurationProvider<T> implements Runnable {
1491
1492 protected final ConfigurationImpl config;
1493 protected final long revision;
1494 protected final Dictionary<String, ?> properties;
1495 protected final BaseTracker<T> helper;
1496
1497 protected ConfigurationProvider(final ConfigurationImpl config) {
1498 this.config = config;
1499 this.helper = ( BaseTracker<T> ) ( ( config.getFactoryPid() == null ) ? managedServiceTracker : managedServiceFactoryTracker );
1500 synchronized ( config )
1501 {
1502 this.revision = config.getRevision();
1503 this.properties = config.getProperties( true );
1504 }
1505 }
1506
1507 protected TargetedPID getTargetedServicePid() {
1508 final String factoryPid = this.config.getFactoryPid();
1509 if (factoryPid == null) {
1510 return new TargetedPID( this.config.getPid() );
1511 }
1512 return new TargetedPID( factoryPid );
1513 }
1514
1515 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001516
1517 /**
1518 * The <code>UpdateConfiguration</code> is used to update
1519 * <code>ManagedService[Factory]</code> services with the configuration
1520 * they are subscribed to. This may cause the configuration to be
1521 * supplied to multiple services.
1522 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001523 private class UpdateConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001524 {
1525
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001526 UpdateConfiguration( final ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001527 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001528 super( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001529 }
1530
1531
1532 public void run()
1533 {
Felix Meschberger61207232011-11-17 10:06:45 +00001534 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1535 { config.getPid(), new Long( revision ) } );
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001536
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001537 final List<ServiceReference<?>> srList = this.helper.getServices( getTargetedServicePid() );
1538 if ( !srList.isEmpty() )
Felix Meschberger41cce522009-08-19 05:54:40 +00001539 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001540 // optionally bind dynamically to the first service
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001541 config.tryBindLocation( srList.get( 0 ).getBundle().getLocation() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001542
1543 final String configBundleLocation = config.getBundleLocation();
1544
1545 // provide configuration to all services from the
1546 // correct bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001547 for (ServiceReference<?> ref : srList)
Felix Meschberger41cce522009-08-19 05:54:40 +00001548 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001549 final Bundle refBundle = ref.getBundle();
1550 if ( refBundle == null )
Felix Meschberger41cce522009-08-19 05:54:40 +00001551 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001552 log( LogService.LOG_DEBUG,
1553 "Service {0} seems to be unregistered concurrently (not providing configuration)",
1554 new Object[]
1555 { ConfigurationManager.toString( ref ) } );
1556 }
1557 else if ( canReceive( refBundle, configBundleLocation ) )
1558 {
Felix Meschbergeraccd9012012-07-02 15:18:08 +00001559 helper.provideConfiguration( ref, this.config, this.properties );
Felix Meschberger2444da62011-11-17 11:17:50 +00001560 }
1561 else
1562 {
1563 // CM 1.4 / 104.13.2.2
Felix Meschberger4f269292011-10-21 13:52:31 +00001564 log( LogService.LOG_ERROR,
1565 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1566 new Object[]
1567 { config.getPid(), ConfigurationManager.toString( ref ), configBundleLocation } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001568 }
1569
Felix Meschberger41cce522009-08-19 05:54:40 +00001570 }
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001571 }
Felix Meschberger137ee722011-11-16 09:51:59 +00001572 else if ( isLogEnabled( LogService.LOG_DEBUG ) )
1573 {
Felix Meschberger1ee888d2011-11-16 12:42:57 +00001574 log( LogService.LOG_DEBUG, "No ManagedService[Factory] registered for updates to configuration {0}",
Felix Meschberger137ee722011-11-16 09:51:59 +00001575 new Object[]
1576 { config.getPid() } );
1577 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001578 }
1579
1580
Felix Meschberger432e3872008-03-07 14:58:57 +00001581 public String toString()
1582 {
1583 return "Update: pid=" + config.getPid();
1584 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001585 }
1586
Felix Meschberger007c50e2011-10-20 12:39:38 +00001587
1588 /**
1589 * The <code>DeleteConfiguration</code> class is used to inform
1590 * <code>ManagedService[Factory]</code> services of a configuration
1591 * being deleted.
1592 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001593 private class DeleteConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001594 {
Felix Meschberger66423332007-08-22 08:46:34 +00001595
Felix Meschbergerc12db8c2009-08-19 06:43:59 +00001596 private final String configLocation;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001597
1598
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001599 DeleteConfiguration( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001600 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001601 /*
1602 * NOTE: We keep the configuration because it might be cleared just
1603 * after calling this method. The pid and factoryPid fields are
1604 * final and cannot be reset.
1605 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001606 super(config);
Felix Meschberger007c50e2011-10-20 12:39:38 +00001607 this.configLocation = config.getBundleLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001608 }
1609
1610
1611 public void run()
1612 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001613 final String pid = config.getPid();
1614 final String factoryPid = config.getFactoryPid();
1615
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001616 List<ServiceReference<?>> srList = this.helper.getServices( getTargetedServicePid() );
1617 if ( !srList.isEmpty() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001618 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001619 for (ServiceReference<?> sr : srList)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001620 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001621 final Bundle srBundle = sr.getBundle();
1622 if ( srBundle == null )
1623 {
1624 log( LogService.LOG_DEBUG,
1625 "Service {0} seems to be unregistered concurrently (not removing configuration)",
1626 new Object[]
1627 { ConfigurationManager.toString( sr ) } );
1628 }
1629 else if ( canReceive( srBundle, configLocation ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001630 {
Felix Meschbergeraccd9012012-07-02 15:18:08 +00001631 this.helper.removeConfiguration( sr, this.config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001632 }
Felix Meschberger2444da62011-11-17 11:17:50 +00001633 else
1634 {
1635 // CM 1.4 / 104.13.2.2
1636 log( LogService.LOG_ERROR,
1637 "Cannot remove configuration {0} for {1}: No visibility to configuration bound to {2}",
1638 new Object[]
1639 { config.getPid(), ConfigurationManager.toString( sr ), configLocation } );
1640 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001641 }
1642 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001643
1644 if ( factoryPid != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001645 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001646 // remove the pid from the factory
1647 try
1648 {
1649 Factory factory = getFactory( factoryPid );
1650 factory.removePID( pid );
1651 factory.store();
1652 }
1653 catch ( IOException ioe )
1654 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001655 log( LogService.LOG_ERROR, "Failed removing {0} from the factory {1}", new Object[]
1656 { pid, factoryPid, ioe } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001657 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001658 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001659 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001660
Felix Meschberger432e3872008-03-07 14:58:57 +00001661 public String toString()
1662 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001663 return "Delete: pid=" + config.getPid();
Felix Meschberger432e3872008-03-07 14:58:57 +00001664 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001665 }
1666
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001667 private class LocationChanged extends ConfigurationProvider
Felix Meschberger007c50e2011-10-20 12:39:38 +00001668 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001669 private final String oldLocation;
1670
1671
1672 LocationChanged( ConfigurationImpl config, String oldLocation )
1673 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001674 super( config );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001675 this.oldLocation = oldLocation;
1676 }
1677
1678
1679 public void run()
1680 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001681 List<ServiceReference<?>> srList = helper.getServices( getTargetedServicePid() );
1682 if ( !srList.isEmpty() )
Felix Meschberger007c50e2011-10-20 12:39:38 +00001683 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001684 for (final ServiceReference<?> sr : srList)
Felix Meschberger007c50e2011-10-20 12:39:38 +00001685 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001686 final Bundle srBundle = sr.getBundle();
1687 if ( srBundle == null )
1688 {
1689 log( LogService.LOG_DEBUG,
1690 "Service {0} seems to be unregistered concurrently (not processing)", new Object[]
1691 { ConfigurationManager.toString( sr ) } );
1692 continue;
1693 }
1694
1695 final boolean wasVisible = canReceive( srBundle, oldLocation );
1696 final boolean isVisible = canReceive( srBundle, config.getBundleLocation() );
1697
1698 // make sure the config is dynamically bound to the first
1699 // service if the config has been unbound causing this update
1700 if ( isVisible )
1701 {
1702 config.tryBindLocation( srBundle.getLocation() );
1703 }
1704
Felix Meschberger007c50e2011-10-20 12:39:38 +00001705 if ( wasVisible && !isVisible )
1706 {
1707 // call deleted method
Felix Meschbergeraccd9012012-07-02 15:18:08 +00001708 helper.removeConfiguration( sr, this.config );
Felix Meschberger4f269292011-10-21 13:52:31 +00001709 log( LogService.LOG_DEBUG, "Configuration {0} revoked from {1} (no more visibility)",
1710 new Object[]
1711 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001712 }
1713 else if ( !wasVisible && isVisible )
1714 {
1715 // call updated method
Felix Meschbergeraccd9012012-07-02 15:18:08 +00001716 helper.provideConfiguration( sr, this.config, this.properties );
Felix Meschberger4f269292011-10-21 13:52:31 +00001717 log( LogService.LOG_DEBUG, "Configuration {0} provided to {1} (new visibility)", new Object[]
1718 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger35658d52011-10-20 21:43:58 +00001719 }
Felix Meschberger4f269292011-10-21 13:52:31 +00001720 else
Felix Meschberger35658d52011-10-20 21:43:58 +00001721 {
1722 // same visibility as before
Felix Meschberger4f269292011-10-21 13:52:31 +00001723 log( LogService.LOG_DEBUG, "Unmodified visibility to configuration {0} for {1}", new Object[]
1724 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001725 }
1726 }
1727 }
1728 }
1729
1730
1731 public String toString()
1732 {
1733 return "Location Changed (pid=" + config.getPid() + "): " + oldLocation + " ==> "
1734 + config.getBundleLocation();
1735 }
1736 }
1737
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001738 private class FireConfigurationEvent implements Runnable
1739 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001740 private final int type;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001741
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001742 private final String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001743
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001744 private final String factoryPid;
1745
1746 private final ServiceReference[] listenerReferences;
1747
1748 private final ConfigurationListener[] listeners;
1749
1750 private final Bundle[] listenerProvider;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001751
Felix Meschberger0770cad2012-06-11 12:36:52 +00001752 private ConfigurationEvent event;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001753
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001754 private FireConfigurationEvent( final int type, final String pid, final String factoryPid)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001755 {
1756 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001757 this.pid = pid;
1758 this.factoryPid = factoryPid;
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001759
1760 final ServiceReference[] srs = configurationListenerTracker.getServiceReferences();
1761 if ( srs == null || srs.length == 0 )
1762 {
1763 this.listenerReferences = null;
1764 this.listeners = null;
1765 this.listenerProvider = null;
1766 }
1767 else
1768 {
1769 this.listenerReferences = srs;
1770 this.listeners = new ConfigurationListener[srs.length];
1771 this.listenerProvider = new Bundle[srs.length];
1772 for ( int i = 0; i < srs.length; i++ )
1773 {
1774 this.listeners[i] = ( ConfigurationListener ) configurationListenerTracker.getService( srs[i] );
1775 this.listenerProvider[i] = srs[i].getBundle();
1776 }
1777 }
1778 }
1779
1780
Felix Meschberger0770cad2012-06-11 12:36:52 +00001781 void fireSynchronousEvents()
1782 {
1783 if ( hasConfigurationEventListeners() && getServiceReference() != null )
1784 {
1785 for ( int i = 0; i < this.listeners.length; i++ )
1786 {
1787 if ( this.listeners[i] instanceof SynchronousConfigurationListener )
1788 {
1789 sendEvent( i );
1790 }
1791 }
1792 }
1793 }
1794
1795
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001796 boolean hasConfigurationEventListeners()
1797 {
1798 return this.listenerReferences != null;
1799 }
1800
1801
1802 String getTypeName()
1803 {
1804 switch ( type )
1805 {
1806 case ConfigurationEvent.CM_DELETED:
1807 return "CM_DELETED";
1808 case ConfigurationEvent.CM_UPDATED:
1809 return "CM_UPDATED";
Felix Meschberger007c50e2011-10-20 12:39:38 +00001810 case ConfigurationEvent.CM_LOCATION_CHANGED:
1811 return "CM_LOCATION_CHANGED";
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001812 default:
1813 return "<UNKNOWN(" + type + ")>";
1814 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001815 }
1816
1817
1818 public void run()
1819 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001820 for ( int i = 0; i < listeners.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001821 {
Felix Meschberger0770cad2012-06-11 12:36:52 +00001822 sendEvent( i );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001823 }
1824 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001825
Felix Meschberger0770cad2012-06-11 12:36:52 +00001826
Felix Meschberger432e3872008-03-07 14:58:57 +00001827 public String toString()
1828 {
1829 return "Fire ConfigurationEvent: pid=" + pid;
1830 }
Felix Meschberger0770cad2012-06-11 12:36:52 +00001831
1832
1833 private ConfigurationEvent getConfigurationEvent()
1834 {
1835 if ( event == null )
1836 {
1837 this.event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
1838 }
1839 return event;
1840 }
1841
1842
1843 private void sendEvent( final int serviceIndex )
1844 {
1845 if ( listenerProvider[serviceIndex].getState() == Bundle.ACTIVE && this.listeners[serviceIndex] != null )
1846 {
1847 log( LogService.LOG_DEBUG, "Sending {0} event for {1} to {2}", new Object[]
1848 { getTypeName(), pid, ConfigurationManager.toString( listenerReferences[serviceIndex] ) } );
1849
1850 try
1851 {
1852 listeners[serviceIndex].configurationEvent( getConfigurationEvent() );
1853 }
1854 catch ( Throwable t )
1855 {
1856 log( LogService.LOG_ERROR, "Unexpected problem delivering configuration event to {0}", new Object[]
1857 { ConfigurationManager.toString( listenerReferences[serviceIndex] ), t } );
1858 }
1859 finally
1860 {
1861 this.listeners[serviceIndex] = null;
1862 }
1863 }
1864 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001865 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001866}