blob: fd5ca095b12f5d0efb727d4c72c8dd83ae0d45b2 [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;
Felix Meschbergerc0894f32012-07-04 08:09:55 +000032import java.util.LinkedList;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000033import java.util.List;
34import java.util.Map;
35import java.util.Random;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000036
37import org.apache.felix.cm.PersistenceManager;
38import org.apache.felix.cm.file.FilePersistenceManager;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000039import org.apache.felix.cm.impl.helper.BaseTracker;
40import org.apache.felix.cm.impl.helper.ManagedServiceFactoryTracker;
41import org.apache.felix.cm.impl.helper.ManagedServiceTracker;
42import org.apache.felix.cm.impl.helper.TargetedPID;
43import org.osgi.framework.Bundle;
44import org.osgi.framework.BundleActivator;
45import org.osgi.framework.BundleContext;
46import org.osgi.framework.BundleEvent;
47import org.osgi.framework.BundleListener;
48import org.osgi.framework.Constants;
49import org.osgi.framework.Filter;
50import org.osgi.framework.InvalidSyntaxException;
51import org.osgi.framework.ServiceReference;
52import org.osgi.framework.ServiceRegistration;
53import org.osgi.service.cm.ConfigurationAdmin;
54import org.osgi.service.cm.ConfigurationEvent;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000055import org.osgi.service.cm.ConfigurationListener;
56import org.osgi.service.cm.ConfigurationPermission;
57import org.osgi.service.cm.ConfigurationPlugin;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000058import org.osgi.service.cm.SynchronousConfigurationListener;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000059import org.osgi.service.log.LogService;
60import org.osgi.util.tracker.ServiceTracker;
61
62
63/**
64 * The <code>ConfigurationManager</code> is the central class in this
65 * implementation of the Configuration Admin Service Specification. As such it
66 * has the following tasks:
67 * <ul>
68 * <li>It is a <code>BundleActivator</code> which is called when the bundle
69 * is started and stopped.
70 * <li>It is a <code>BundleListener</code> which gets informed when the
71 * states of bundles change. Mostly this is needed to unbind any bound
72 * configuration in case a bundle is uninstalled.
73 * <li>It is a <code>ServiceListener</code> which gets informed when
74 * <code>ManagedService</code> and <code>ManagedServiceFactory</code>
75 * services are registered and unregistered. This is used to provide
76 * configuration to these services. As a service listener it also listens for
77 * {@link PersistenceManager} instances being registered to support different
78 * configuration persistence layers.
79 * <li>A {@link ConfigurationAdminFactory} instance is registered as the
80 * <code>ConfigurationAdmin</code> service.
81 * <li>A {@link FilePersistenceManager} instance is registered as a default
82 * {@link PersistenceManager}.
83 * <li>Last but not least this instance manages all tasks laid out in the
84 * specification such as maintaining configuration, taking care of configuration
85 * events, etc.
86 * </ul>
87 * <p>
88 * The default {@link FilePersistenceManager} is configured with a configuration
89 * location taken from the <code>felix.cm.dir</code> framework property. If
90 * this property is not set the <code>config</code> directory in the current
91 * working directory as specified in the <code>user.dir</code> system property
92 * is used.
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000093 */
94public class ConfigurationManager implements BundleActivator, BundleListener
95{
96
97 /**
98 * The name of the bundle context property defining the location for the
99 * configuration files (value is "felix.cm.dir").
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000100 *
Carsten Ziegeler7853b9a2008-01-11 16:30:24 +0000101 * @see #start(BundleContext)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000102 */
103 public static final String CM_CONFIG_DIR = "felix.cm.dir";
104
Felix Meschberger08282c32009-01-28 07:01:55 +0000105 /**
106 * The name of the bundle context property defining the maximum log level
107 * (value is "felix.cm.loglevel"). The log level setting is only used if
108 * there is no OSGi LogService available. Otherwise this setting is ignored.
109 * <p>
110 * This value of this property is expected to be an integer number
111 * corresponding to the log level values of the OSGi LogService. That is 1
112 * for errors, 2 for warnings, 3 for informational messages and 4 for debug
113 * messages. The default value is 2, such that only warnings and errors are
114 * logged in the absence of a LogService.
115 */
116 public static final String CM_LOG_LEVEL = "felix.cm.loglevel";
117
Felix Meschberger85b355d2007-08-31 07:17:38 +0000118 // The name of the LogService (not using the class, which might be missing)
119 private static final String LOG_SERVICE_NAME = "org.osgi.service.log.LogService";
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000120
Felix Meschberger08282c32009-01-28 07:01:55 +0000121 private static final int CM_LOG_LEVEL_DEFAULT = 2;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000122
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000123 // random number generator to create configuration PIDs for factory
124 // configurations
Felix Meschberger417f66c2011-02-04 11:25:23 +0000125 private static Random numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000126
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000127 // the BundleContext of the Configuration Admin Service bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000128 BundleContext bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000129
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000130 // the service registration of the configuration admin
Felix Meschberger4b26df92011-02-01 12:41:45 +0000131 private volatile ServiceRegistration configurationAdminRegistration;
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000132
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000133 // the ServiceTracker to emit log services (see log(int, String, Throwable))
134 private ServiceTracker logTracker;
135
136 // the ConfigurationEvent listeners
137 private ServiceTracker configurationListenerTracker;
138
139 // service tracker for managed services
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000140 private ManagedServiceTracker managedServiceTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000141
142 // service tracker for managed service factories
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000143 private ManagedServiceFactoryTracker managedServiceFactoryTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000144
145 // PersistenceManager services
146 private ServiceTracker persistenceManagerTracker;
147
148 // the thread used to schedule tasks required to run asynchronously
149 private UpdateThread updateThread;
150
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000151 // the thread used to schedule events to be dispatched asynchronously
152 private UpdateThread eventThread;
153
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000154 /**
155 * The actual list of {@link PersistenceManager persistence managers} to use
156 * when looking for configuration data. This list is built from the
157 * {@link #persistenceManagerMap}, which is ordered according to the
158 * {@link RankingComparator}.
159 */
160 private PersistenceManager[] persistenceManagers;
161
162 // the persistenceManagerTracker.getTrackingCount when the
163 // persistenceManagers were last got
164 private int pmtCount;
165
166 // the cache of Factory instances mapped by their factory PID
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000167 private final HashMap<String, Factory> factories = new HashMap<String, Factory>();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000168
169 // the cache of Configuration instances mapped by their PID
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000170 // have this always set to prevent NPE on bundle shutdown
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000171 private final HashMap<String, ConfigurationImpl> configurations = new HashMap<String, ConfigurationImpl>();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000172
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000173 /**
174 * The map of dynamic configuration bindings. This maps the
175 * PID of the dynamically bound configuration or factory to its bundle
176 * location.
177 * <p>
178 * On bundle startup this map is loaded from persistence and validated
179 * against the locations of installed bundles: Entries pointing to bundle
180 * locations not currently installed are removed.
181 * <p>
182 * The map is written to persistence on each change.
183 */
184 private DynamicBindings dynamicBindings;
185
Felix Meschberger08282c32009-01-28 07:01:55 +0000186 // the maximum log level when no LogService is available
187 private int logLevel = CM_LOG_LEVEL_DEFAULT;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000188
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000189 // flag indicating whether BundleChange events should be consumed (FELIX-979)
190 private volatile boolean handleBundleEvents;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000191
Felix Meschberger623f7142012-01-31 07:13:37 +0000192 // flag indicating whether the manager is considered alive
193 private volatile boolean isActive;
194
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000195 public void start( BundleContext bundleContext )
196 {
197 // track the log service using a ServiceTracker
Felix Meschberger85b355d2007-08-31 07:17:38 +0000198 logTracker = new ServiceTracker( bundleContext, LOG_SERVICE_NAME , null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000199 logTracker.open();
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000200
Felix Meschberger08282c32009-01-28 07:01:55 +0000201 // assign the log level
202 String logLevelProp = bundleContext.getProperty( CM_LOG_LEVEL );
203 if ( logLevelProp == null )
204 {
205 logLevel = CM_LOG_LEVEL_DEFAULT;
206 }
207 else
208 {
209 try
210 {
211 logLevel = Integer.parseInt( logLevelProp );
212 }
213 catch ( NumberFormatException nfe )
214 {
215 logLevel = CM_LOG_LEVEL_DEFAULT;
216 }
217 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000218
219 // set up some fields
220 this.bundleContext = bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000221
222 // configurationlistener support
223 configurationListenerTracker = new ServiceTracker( bundleContext, ConfigurationListener.class.getName(), null );
224 configurationListenerTracker.open();
225
226 // initialize the asynchonous updater thread
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000227 ThreadGroup tg = new ThreadGroup( "Configuration Admin Service" );
228 tg.setDaemon( true );
229 this.updateThread = new UpdateThread( this, tg, "CM Configuration Updater" );
230 this.eventThread = new UpdateThread( this, tg, "CM Event Dispatcher" );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000231
232 // set up the location (might throw IllegalArgumentException)
233 try
234 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000235 FilePersistenceManager fpm = new FilePersistenceManager( bundleContext, bundleContext
236 .getProperty( CM_CONFIG_DIR ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000237 Hashtable props = new Hashtable();
238 props.put( Constants.SERVICE_PID, fpm.getClass().getName() );
239 props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
240 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
241 props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
242 bundleContext.registerService( PersistenceManager.class.getName(), fpm, props );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000243
244 // setup dynamic configuration bindings
245 dynamicBindings = new DynamicBindings( bundleContext, fpm );
246 }
247 catch ( IOException ioe )
248 {
249 log( LogService.LOG_ERROR, "Failure setting up dynamic configuration bindings", ioe );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000250 }
251 catch ( IllegalArgumentException iae )
252 {
253 log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
254 }
255
256 // register as bundle and service listener
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000257 handleBundleEvents = true;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000258 bundleContext.addBundleListener( this );
259
260 // get all persistence managers to begin with
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000261 pmtCount = 1; // make sure to get the persistence managers at least once
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000262 persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
263 persistenceManagerTracker.open();
264
Felix Meschberger623f7142012-01-31 07:13:37 +0000265 // consider alive now (before clients use Configuration Admin
266 // service registered in the next step)
267 isActive = true;
268
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000269 // create and register configuration admin - start after PM tracker ...
270 ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
271 Hashtable props = new Hashtable();
272 props.put( Constants.SERVICE_PID, "org.apache.felix.cm.ConfigurationAdmin" );
273 props.put( Constants.SERVICE_DESCRIPTION, "Configuration Admin Service Specification 1.2 Implementation" );
274 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000275 configurationAdminRegistration = bundleContext.registerService( ConfigurationAdmin.class.getName(), caf, props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000276
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000277 // start handling ManagedService[Factory] services
278 managedServiceTracker = new ManagedServiceTracker(this);
279 managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this);
280
Felix Meschberger4b26df92011-02-01 12:41:45 +0000281 // start processing the event queues only after registering the service
282 // see FELIX-2813 for details
283 this.updateThread.start();
284 this.eventThread.start();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000285 }
286
287
288 public void stop( BundleContext bundleContext )
289 {
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000290
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000291 // stop handling bundle events immediately
292 handleBundleEvents = false;
293
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000294 // stop handling ManagedService[Factory] services
295 managedServiceFactoryTracker.close();
296 managedServiceTracker.close();
297
Felix Meschberger4b26df92011-02-01 12:41:45 +0000298 // stop queue processing before unregistering the service
299 // see FELIX-2813 for details
300 if ( updateThread != null )
301 {
302 updateThread.terminate();
303 }
304 if ( eventThread != null )
305 {
306 eventThread.terminate();
307 }
308
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000309 // immediately unregister the Configuration Admin before cleaning up
Felix Meschberger10568352009-01-15 08:57:11 +0000310 // clearing the field before actually unregistering the service
311 // prevents IllegalStateException in getServiceReference() if
312 // the field is not null but the service already unregistered
313 if (configurationAdminRegistration != null) {
314 ServiceRegistration reg = configurationAdminRegistration;
315 configurationAdminRegistration = null;
316 reg.unregister();
317 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000318
Felix Meschberger623f7142012-01-31 07:13:37 +0000319 // consider inactive after unregistering such that during
320 // unregistration the manager is still alive and can react
321 isActive = false;
322
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000323 // don't care for PersistenceManagers any more
324 persistenceManagerTracker.close();
325
326 // stop listening for events
327 bundleContext.removeBundleListener( this );
328
329 if ( configurationListenerTracker != null )
330 {
331 configurationListenerTracker.close();
332 }
333
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000334 if ( logTracker != null )
335 {
336 logTracker.close();
337 }
338
Felix Meschberger6a698df2009-08-16 18:38:46 +0000339 // just ensure the configuration cache is empty
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000340 synchronized ( configurations )
341 {
342 configurations.clear();
343 }
344
Felix Meschberger6a698df2009-08-16 18:38:46 +0000345 // just ensure the factory cache is empty
346 synchronized ( factories )
347 {
348 factories.clear();
349 }
350
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000351 this.bundleContext = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000352 }
353
354
Felix Meschberger623f7142012-01-31 07:13:37 +0000355 /**
356 * Returns <code>true</code> if this manager is considered active.
357 */
358 boolean isActive()
359 {
360 return isActive;
361 }
362
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000363 public BundleContext getBundleContext()
364 {
365 return bundleContext;
366 }
Felix Meschberger623f7142012-01-31 07:13:37 +0000367
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000368 // ---------- Configuration caching support --------------------------------
369
370 ConfigurationImpl getCachedConfiguration( String pid )
371 {
372 synchronized ( configurations )
373 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000374 return configurations.get( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000375 }
376 }
377
378
Felix Meschberger6a698df2009-08-16 18:38:46 +0000379 ConfigurationImpl[] getCachedConfigurations()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000380 {
381 synchronized ( configurations )
382 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000383 return configurations.values().toArray(
Felix Meschberger6a698df2009-08-16 18:38:46 +0000384 new ConfigurationImpl[configurations.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000385 }
386 }
387
388
Felix Meschberger2941ef92007-08-20 13:15:16 +0000389 ConfigurationImpl cacheConfiguration( ConfigurationImpl configuration )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000390 {
391 synchronized ( configurations )
392 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000393 final String pid = configuration.getPidString();
394 final Object existing = configurations.get( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000395 if ( existing != null )
396 {
397 return ( ConfigurationImpl ) existing;
398 }
399
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000400 configurations.put( pid, configuration );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000401 return configuration;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000402 }
403 }
404
405
406 void removeConfiguration( ConfigurationImpl configuration )
407 {
408 synchronized ( configurations )
409 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000410 configurations.remove( configuration.getPidString() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000411 }
412 }
413
414
Felix Meschberger6a698df2009-08-16 18:38:46 +0000415 Factory getCachedFactory( String factoryPid )
416 {
417 synchronized ( factories )
418 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000419 return factories.get( factoryPid );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000420 }
421 }
422
423
424 Factory[] getCachedFactories()
425 {
426 synchronized ( factories )
427 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000428 return factories.values().toArray( new Factory[factories.size()] );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000429 }
430 }
431
432
433 void cacheFactory( Factory factory )
434 {
435 synchronized ( factories )
436 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000437 factories.put( factory.getFactoryPidString(), factory );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000438 }
439 }
440
441
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000442 // ---------- ConfigurationAdminImpl support
Felix Meschberger6a698df2009-08-16 18:38:46 +0000443
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000444 void setDynamicBundleLocation( final String pid, final String location )
445 {
446 if ( dynamicBindings != null )
447 {
448 try
449 {
450 dynamicBindings.putLocation( pid, location );
451 }
452 catch ( IOException ioe )
453 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000454 log( LogService.LOG_ERROR, "Failed storing dynamic configuration binding for {0} to {1}", new Object[]
455 { pid, location, ioe } );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000456 }
457 }
458 }
459
460
461 String getDynamicBundleLocation( final String pid )
462 {
463 if ( dynamicBindings != null )
464 {
465 return dynamicBindings.getLocation( pid );
466 }
467
468 return null;
469 }
470
471
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000472 ConfigurationImpl createFactoryConfiguration( String factoryPid, String location ) throws IOException
473 {
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000474 return cacheConfiguration( createConfiguration( createPid( factoryPid ), factoryPid, location ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000475 }
476
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000477 /**
478 * Returns a targeted configuration for the given service PID and
479 * the reference target service.
480 *
481 * @param rawPid The raw service PID to get targeted configuration for.
482 * @param target The target <code>ServiceReference</code> to get
483 * configuration for.
484 * @return The best matching targeted configuration or <code>null</code>
485 * if there is no configuration at all.
486 * @throwss IOException if an error occurrs reading configurations
487 * from persistence.
488 */
489 ConfigurationImpl getTargetedConfiguration( final String rawPid, final ServiceReference target ) throws IOException
490 {
491 final Bundle serviceBundle = target.getBundle();
492 if ( serviceBundle != null )
493 {
494 // for pre-1.5 API compatibility
495 final StringBuffer targetedPid = new StringBuffer( rawPid );
496 int i = 3;
497 String[] names = new String[4];
498 names[i--] = targetedPid.toString();
499 targetedPid.append( '|' ).append( serviceBundle.getSymbolicName() );
500 names[i--] = targetedPid.toString();
501 targetedPid.append( '|' ).append( TargetedPID.getBundleVersion( serviceBundle ) );
502 names[i--] = targetedPid.toString();
503 targetedPid.append( '|' ).append( serviceBundle.getLocation() );
504 names[i--] = targetedPid.toString();
505
506 for ( String candidate : names )
507 {
508 ConfigurationImpl config = getConfiguration( candidate );
509 if ( config != null )
510 {
511 return config;
512 }
513 }
514 }
515
516 // service already unregistered, nothing to do really
517 return null;
518 }
519
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000520
Felix Meschbergerad949872011-11-16 10:34:54 +0000521 /**
522 * Returns the {@link ConfigurationImpl} with the given PID if
523 * available in the internal cache or from any persistence manager.
524 * Otherwise <code>null</code> is returned.
525 *
526 * @param pid The PID for which to return the configuration
527 * @return The configuration or <code>null</code> if non exists
528 * @throws IOException If an error occurrs reading from a persistence
529 * manager.
530 */
531 ConfigurationImpl getConfiguration( String pid ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000532 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000533 ConfigurationImpl config = getCachedConfiguration( pid );
534 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000535 {
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000536 log( LogService.LOG_DEBUG, "Found cached configuration {0} bound to {1}", new Object[]
537 { pid, config.getBundleLocation() } );
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000538
539 config.ensureFactoryConfigPersisted();
540
Felix Meschberger2941ef92007-08-20 13:15:16 +0000541 return config;
542 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000543
Felix Meschberger2941ef92007-08-20 13:15:16 +0000544 PersistenceManager[] pmList = getPersistenceManagers();
545 for ( int i = 0; i < pmList.length; i++ )
546 {
547 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000548 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000549 Dictionary props = pmList[i].load( pid );
550 config = new ConfigurationImpl( this, pmList[i], props );
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000551 log( LogService.LOG_DEBUG, "Found existing configuration {0} bound to {1}", new Object[]
552 { pid, config.getBundleLocation() } );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000553 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000554 }
555 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000556
Felix Meschberger2941ef92007-08-20 13:15:16 +0000557 // neither the cache nor any persistence manager has configuration
558 return null;
559 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000560
561
Felix Meschbergerad949872011-11-16 10:34:54 +0000562 /**
563 * Creates a regular (non-factory) configuration for the given PID
564 * setting the bundle location accordingly.
565 * <p>
566 * This method assumes the configuration to not exist yet and will
567 * create it without further checking.
568 *
569 * @param pid The PID of the new configuration
570 * @param bundleLocation The location to set on the new configuration.
571 * This may be <code>null</code> to not bind the configuration
572 * yet.
573 * @return The new configuration persisted in the first persistence
574 * manager.
575 * @throws IOException If an error occurrs writing the configuration
576 * to the persistence.
577 */
578 ConfigurationImpl createConfiguration( String pid, String bundleLocation ) throws IOException
Felix Meschberger2941ef92007-08-20 13:15:16 +0000579 {
580 // check for existing (cached or persistent) configuration
Felix Meschbergerad949872011-11-16 10:34:54 +0000581 ConfigurationImpl config = getConfiguration( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000582 if ( config != null )
583 {
584 return config;
585 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000586
Felix Meschberger2941ef92007-08-20 13:15:16 +0000587 // else create new configuration also setting the bundle location
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000588 // and cache the new configuration
589 config = createConfiguration( pid, null, bundleLocation );
590 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000591 }
592
593
594 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
595 throws IOException, InvalidSyntaxException
596 {
597 Filter filter = null;
598 if ( filterString != null )
599 {
600 filter = bundleContext.createFilter( filterString );
601 }
602
Felix Meschberger4f269292011-10-21 13:52:31 +0000603 log( LogService.LOG_DEBUG, "Listing configurations matching {0}", new Object[]
604 { filterString } );
605
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000606 List configList = new ArrayList();
607
608 PersistenceManager[] pmList = getPersistenceManagers();
609 for ( int i = 0; i < pmList.length; i++ )
610 {
611 Enumeration configs = pmList[i].getDictionaries();
612 while ( configs.hasMoreElements() )
613 {
614 Dictionary config = ( Dictionary ) configs.nextElement();
615
616 // ignore non-Configuration dictionaries
Felix Meschberger86a0d172007-07-04 07:15:01 +0000617 String pid = ( String ) config.get( Constants.SERVICE_PID );
618 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000619 {
620 continue;
621 }
622
Felix Meschberger007c50e2011-10-20 12:39:38 +0000623 // CM 1.4 / 104.13.2.3 Permission required
624 if ( !configurationAdmin.hasPermission( ( String ) config
625 .get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000626 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000627 log(
628 LogService.LOG_DEBUG,
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000629 "Omitting configuration {0}: No permission for bundle {1} on configuration bound to {2}",
Felix Meschberger4f269292011-10-21 13:52:31 +0000630 new Object[]
631 { config.get( Constants.SERVICE_PID ), configurationAdmin.getBundle().getLocation(),
632 config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000633 continue;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000634 }
635
636 // check filter
637 if ( filter == null || filter.match( config ) )
638 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000639 // ensure the service.pid and returned a cached config if available
640 ConfigurationImpl cfg = getCachedConfiguration( pid );
641 if ( cfg == null )
642 {
643 cfg = new ConfigurationImpl( this, pmList[i], config );
644 }
645
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000646 // FELIX-611: Ignore configuration objects without props
647 if ( !cfg.isNew() )
648 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000649 log( LogService.LOG_DEBUG, "Adding configuration {0}", new Object[]
650 { config.get( Constants.SERVICE_PID ) } );
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000651 configList.add( cfg );
652 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000653 else
654 {
655 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Is new", new Object[]
656 { config.get( Constants.SERVICE_PID ) } );
657 }
658 } else {
659 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Does not match filter", new Object[]
660 { config.get( Constants.SERVICE_PID ) } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000661 }
662 }
663 }
664
Felix Meschberger8faceff2007-07-04 07:19:48 +0000665 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000666 .size()] );
667 }
668
669
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000670 void deleted( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000671 {
672 // remove the configuration from the cache
673 removeConfiguration( config );
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000674 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000675 updateThread.schedule( new DeleteConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000676 log( LogService.LOG_DEBUG, "DeleteConfiguration({0}) scheduled", new Object[]
677 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000678 }
679
680
Felix Meschbergerce67d732009-08-20 06:26:35 +0000681 void updated( ConfigurationImpl config, boolean fireEvent )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000682 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000683 if ( fireEvent )
684 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000685 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000686 }
687 updateThread.schedule( new UpdateConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000688 log( LogService.LOG_DEBUG, "UpdateConfiguration({0}) scheduled", new Object[]
689 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000690 }
691
692
Felix Meschberger007c50e2011-10-20 12:39:38 +0000693 void locationChanged( ConfigurationImpl config, String oldLocation )
694 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000695 fireConfigurationEvent( ConfigurationEvent.CM_LOCATION_CHANGED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger35658d52011-10-20 21:43:58 +0000696 if ( oldLocation != null && !config.isNew() )
Felix Meschberger007c50e2011-10-20 12:39:38 +0000697 {
698 updateThread.schedule( new LocationChanged( config, oldLocation ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000699 log( LogService.LOG_DEBUG, "LocationChanged({0}, {1}=>{2}) scheduled", new Object[]
700 { config.getPid(), oldLocation, config.getBundleLocation() } );
Felix Meschberger35658d52011-10-20 21:43:58 +0000701 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000702 else
Felix Meschberger35658d52011-10-20 21:43:58 +0000703 {
704 log( LogService.LOG_DEBUG,
Felix Meschberger4f269292011-10-21 13:52:31 +0000705 "LocationChanged not scheduled for {0} (old location is null or configuration is new)", new Object[]
706 { config.getPid() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000707 }
708 }
709
710
Felix Meschberger66423332007-08-22 08:46:34 +0000711 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000712 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000713 FireConfigurationEvent event = new FireConfigurationEvent( type, pid, factoryPid );
Felix Meschberger0770cad2012-06-11 12:36:52 +0000714 event.fireSynchronousEvents();
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000715 if ( event.hasConfigurationEventListeners() )
716 {
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000717 eventThread.schedule( event );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000718 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000719 else
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000720 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000721 log( LogService.LOG_DEBUG, "No ConfigurationListeners to send {0} event to.", new Object[]
722 { event.getTypeName() } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000723 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000724 }
725
726
727 // ---------- BundleListener -----------------------------------------------
728
729 public void bundleChanged( BundleEvent event )
730 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000731 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000732 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000733 final String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000734
Felix Meschberger6a698df2009-08-16 18:38:46 +0000735 // we only reset dynamic bindings, which are only present in
736 // cached configurations, hence only consider cached configs here
737 final ConfigurationImpl[] configs = getCachedConfigurations();
738 for ( int i = 0; i < configs.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000739 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000740 final ConfigurationImpl cfg = configs[i];
Felix Meschberger41cce522009-08-19 05:54:40 +0000741 if ( location.equals( cfg.getDynamicBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000742 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000743 cfg.setDynamicBundleLocation( null, true );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000744 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000745 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000746 }
747 }
748
749
750 // ---------- internal -----------------------------------------------------
751
752 private PersistenceManager[] getPersistenceManagers()
753 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000754 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
755 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000756 {
757
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000758 List pmList = new ArrayList();
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000759 PersistenceManager[] pm;
760
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000761 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
762 if ( refs == null || refs.length == 0 )
763 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000764 pm = new PersistenceManager[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000765 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000766 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000767 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000768 // sort the references according to the cmRanking property
Felix Meschberger007c50e2011-10-20 12:39:38 +0000769 if ( refs.length > 1 )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000770 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000771 Arrays.sort( refs, RankingComparator.SRV_RANKING );
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000772 }
773
774 // create the service array from the sorted set of referenecs
Felix Meschberger007c50e2011-10-20 12:39:38 +0000775 for ( int i = 0; i < refs.length; i++ )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000776 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000777 Object service = persistenceManagerTracker.getService( refs[i] );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000778 if ( service != null )
779 {
Felix Meschbergera86cdfc2010-08-25 09:32:36 +0000780 pmList.add( new CachingPersistenceManagerProxy( ( PersistenceManager ) service ) );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000781 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000782 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000783
784 pm = ( PersistenceManager[] ) pmList.toArray( new PersistenceManager[pmList.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000785 }
786
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000787 pmtCount = pm.length;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000788 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000789 }
790
791 return persistenceManagers;
792 }
793
794
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000795 private ServiceReference getServiceReference()
796 {
797 ServiceRegistration reg = configurationAdminRegistration;
Felix Meschberger0770cad2012-06-11 12:36:52 +0000798 if (reg != null) {
799 return reg.getReference();
800 }
801
802 // probably called for firing an event during service registration
803 // since we didn't get the service registration yet we use the
804 // service registry to get our service reference
805 BundleContext context = bundleContext;
806 if ( context != null )
807 {
808 try
809 {
810 ServiceReference[] refs = context.getServiceReferences( ConfigurationAdmin.class.getName(), null );
811 if ( refs != null )
812 {
813 for ( int i = 0; i < refs.length; i++ )
814 {
815 if ( refs[i].getBundle().getBundleId() == context.getBundle().getBundleId() )
816 {
817 return refs[i];
818 }
819 }
820 }
821 }
822 catch ( InvalidSyntaxException e )
823 {
824 // unexpected since there is no filter
825 }
826 }
827
828 // service references
829 return null;
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000830 }
831
832
Felix Meschberger05d89e12011-11-03 23:37:10 +0000833 /**
834 * Configures the ManagedService and returns the service.pid
835 * service property as a String[], which may be <code>null</code> if
836 * the ManagedService does not have such a property.
837 */
Felix Meschberger05d89e12011-11-03 23:37:10 +0000838 /**
839 * Configures the ManagedServiceFactory and returns the service.pid
840 * service property as a String[], which may be <code>null</code> if
841 * the ManagedServiceFactory does not have such a property.
842 */
Felix Meschberger382a19b2012-07-03 09:45:14 +0000843 /**
844 * Schedules the configuration of the referenced service with
845 * configuration for the given PID.
846 *
847 * @param pid The service PID of the configuration to be provided
848 * to the referenced service.
849 * @param sr The <code>ServiceReference</code> to the service
850 * to be configured.
851 * @param factory <code>true</code> If the service is considered to
852 * be a <code>ManagedServiceFactory</code>. Otherwise the service
853 * is considered to be a <code>ManagedService</code>.
854 */
855 public void configure( String pid, ServiceReference sr, final boolean factory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000856 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000857 Runnable r;
858 if ( factory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000859 {
Felix Meschberger382a19b2012-07-03 09:45:14 +0000860 r = new ManagedServiceFactoryUpdate( pid, sr );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000861 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000862 else
863 {
Felix Meschberger382a19b2012-07-03 09:45:14 +0000864 r = new ManagedServiceUpdate( pid, sr );
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000865 }
866 updateThread.schedule( r );
867 log( LogService.LOG_DEBUG, "[{0}] scheduled", new Object[]
868 { r } );
Felix Meschberger851c6412009-08-16 18:43:26 +0000869 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000870
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000871
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000872 /**
873 * Factory method to create a new configuration object. The configuration
874 * object returned is not stored in configuration cache and only persisted
875 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000876 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000877 * @param pid
878 * The PID of the new configuration object. Must not be
879 * <code>null</code>.
880 * @param factoryPid
881 * The factory PID of the new configuration. Not
Felix Meschberger6a698df2009-08-16 18:38:46 +0000882 * <code>null</code> if the new configuration object belongs to a
883 * factory. The configuration object will not be persisted if
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000884 * this parameter is not <code>null</code>.
885 * @param bundleLocation
886 * The bundle location of the bundle to which the configuration
Felix Meschberger6a698df2009-08-16 18:38:46 +0000887 * belongs or <code>null</code> if the configuration is not bound
888 * yet.
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000889 * @return The new configuration object
890 * @throws IOException
891 * May be thrown if an error occurrs persisting the new
892 * configuration object.
893 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000894 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000895 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000896 log( LogService.LOG_DEBUG, "createConfiguration({0}, {1}, {2})", new Object[]
897 { pid, factoryPid, bundleLocation } );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000898 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000899 }
900
901
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000902 /**
903 * Returns a list of {@link Factory} instances according to the
904 * Configuration Admin 1.5 specification for targeted PIDs (Section
905 * 104.3.2)
906 *
907 * @param rawFactoryPid The raw factory PID without any targetting.
908 * @param target The <code>ServiceReference</code> of the service to
909 * be supplied with targeted configuration.
910 * @return A list of {@link Factory} instances as listed above. This
911 * list will always at least include an instance for the
912 * <code>rawFactoryPid</code>. Other instances are only included
913 * if existing.
914 * @throws IOException If an error occurrs reading any of the
915 * {@link Factory} instances from persistence
916 */
917 List<Factory> getTargetedFactories( final String rawFactoryPid, final ServiceReference target ) throws IOException
918 {
919 LinkedList<Factory> factories = new LinkedList<Factory>();
920
921 final Bundle serviceBundle = target.getBundle();
922 if ( serviceBundle != null )
923 {
924 // for pre-1.5 API compatibility
925 final StringBuffer targetedPid = new StringBuffer( rawFactoryPid );
926 factories.add( getOrCreateFactory( targetedPid.toString() ) );
927
928 targetedPid.append( '|' ).append( serviceBundle.getSymbolicName() );
929 Factory f = getFactory( targetedPid.toString() );
930 if ( f != null )
931 {
932 factories.add( 0, f );
933 }
934
935 targetedPid.append( '|' ).append( TargetedPID.getBundleVersion( serviceBundle ) );
936 f = getFactory( targetedPid.toString() );
937 if ( f != null )
938 {
939 factories.add( 0, f );
940 }
941
942 targetedPid.append( '|' ).append( serviceBundle.getLocation() );
943 f = getFactory( targetedPid.toString() );
944 if ( f != null )
945 {
946 factories.add( 0, f );
947 }
948 }
949
950 return factories;
951 }
952
953
954 /**
955 * Gets the factory with the exact identifier from the cached or from
956 * the persistence managers. If no factory exists already one is
957 * created and cached.
958 *
959 * @param factoryPid The PID of the {@link Factory} to return
960 * @return The existing or newly created {@link Factory}
961 * @throws IOException If an error occurrs reading the factory from
962 * a {@link PersistenceManager}
963 */
964 Factory getOrCreateFactory( String factoryPid ) throws IOException
965 {
966 Factory factory = getFactory( factoryPid );
967 if ( factory != null )
968 {
969 return factory;
970 }
971
972 return createFactory( factoryPid );
973 }
974
975
976 /**
977 * Gets the factory with the exact identifier from the cached or from
978 * the persistence managers. If no factory exists <code>null</code>
979 * is returned.
980 *
981 * @param factoryPid The PID of the {@link Factory} to return
982 * @return The existing {@link Factory} or <code>null</code>
983 * @throws IOException If an error occurrs reading the factory from
984 * a {@link PersistenceManager}
985 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000986 Factory getFactory( String factoryPid ) throws IOException
987 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000988 // check for cached factory
Felix Meschbergerf4631322008-03-10 12:32:35 +0000989 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000990 if ( factory != null )
991 {
992 return factory;
993 }
994
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000995 // try to load factory from persistence
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000996 PersistenceManager[] pmList = getPersistenceManagers();
997 for ( int i = 0; i < pmList.length; i++ )
998 {
999 if ( Factory.exists( pmList[i], factoryPid ) )
1000 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +00001001 factory = Factory.load( this, pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001002 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001003 return factory;
1004 }
1005 }
1006
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001007 // no existing factory
1008 return null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001009 }
1010
1011
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001012 /**
1013 * Creates a new factory with the given <code>factoryPid</code>.
1014 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001015 Factory createFactory( String factoryPid )
1016 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +00001017 Factory factory = new Factory( this, getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001018 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001019 return factory;
1020 }
1021
1022
Felix Meschberger2941ef92007-08-20 13:15:16 +00001023 /**
1024 * Calls the registered configuration plugins on the given configuration
Felix Meschberger41cce522009-08-19 05:54:40 +00001025 * properties from the given configuration object unless the configuration
1026 * has just been created and not been updated yet.
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001027 *
Felix Meschberger41cce522009-08-19 05:54:40 +00001028 * @param props The configuraiton properties run through the registered
1029 * ConfigurationPlugin services. This may be <code>null</code>
1030 * in which case this method just immediately returns.
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001031 * @param targetPid The identification of the configuration update used to
1032 * select the plugins according to their cm.target service
1033 * property
Felix Meschberger2941ef92007-08-20 13:15:16 +00001034 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001035 * is to be updated with configuration
Felix Meschberger2941ef92007-08-20 13:15:16 +00001036 * @param cfg The configuration object whose properties have to be passed
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001037 * through the plugins
Felix Meschberger2941ef92007-08-20 13:15:16 +00001038 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001039 public void callPlugins( final Dictionary props, final String targetPid, final ServiceReference sr,
Felix Meschberger41cce522009-08-19 05:54:40 +00001040 final ConfigurationImpl cfg )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001041 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001042 // guard against NPE for new configuration never updated
1043 if (props == null) {
Felix Meschberger41cce522009-08-19 05:54:40 +00001044 return;
Felix Meschberger2941ef92007-08-20 13:15:16 +00001045 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001046
1047 ServiceReference[] plugins = null;
1048 try
1049 {
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001050 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001051 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001052 }
1053 catch ( InvalidSyntaxException ise )
1054 {
1055 // no filter, no exception ...
1056 }
1057
1058 // abort early if there are no plugins
1059 if ( plugins == null || plugins.length == 0 )
1060 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001061 return;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001062 }
1063
1064 // sort the plugins by their service.cmRanking
Felix Meschberger007c50e2011-10-20 12:39:38 +00001065 if ( plugins.length > 1 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001066 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001067 Arrays.sort( plugins, RankingComparator.CM_RANKING );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001068 }
1069
1070 // call the plugins in order
Felix Meschberger007c50e2011-10-20 12:39:38 +00001071 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001072 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001073 ServiceReference pluginRef = plugins[i];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001074 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001075 if ( plugin != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001076 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001077 try
1078 {
1079 plugin.modifyConfiguration( sr, props );
1080 }
1081 catch ( Throwable t )
1082 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001083 log( LogService.LOG_ERROR, "Unexpected problem calling configuration plugin {0}", new Object[]
1084 { toString( pluginRef ), t } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001085 }
1086 finally
1087 {
1088 // ensure ungetting the plugin
1089 bundleContext.ungetService( pluginRef );
1090 }
1091 cfg.setAutoProperties( props, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001092 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001093 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001094 }
1095
1096
1097 /**
1098 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001099 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001100 * @param factoryPid
1101 * @return
1102 */
1103 private static String createPid( String factoryPid )
1104 {
Felix Meschberger417f66c2011-02-04 11:25:23 +00001105 Random ng = numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001106 if ( ng == null )
1107 {
Felix Meschberger417f66c2011-02-04 11:25:23 +00001108 // FELIX-2771 Secure Random not available on Mika
1109 try
1110 {
1111 ng = new SecureRandom();
1112 }
1113 catch ( Throwable t )
1114 {
1115 // fall back to Random
1116 ng = new Random();
1117 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001118 }
1119
1120 byte[] randomBytes = new byte[16];
1121 ng.nextBytes( randomBytes );
1122 randomBytes[6] &= 0x0f; /* clear version */
1123 randomBytes[6] |= 0x40; /* set to version 4 */
1124 randomBytes[8] &= 0x3f; /* clear variant */
1125 randomBytes[8] |= 0x80; /* set to IETF variant */
1126
1127 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
1128
1129 // prefix the new pid with the factory pid
1130 buf.append( factoryPid ).append( "." );
1131
1132 // serialize the UUID into the buffer
1133 for ( int i = 0; i < randomBytes.length; i++ )
1134 {
1135
1136 if ( i == 4 || i == 6 || i == 8 || i == 10 )
1137 {
1138 buf.append( '-' );
1139 }
1140
1141 int val = randomBytes[i] & 0xff;
1142 buf.append( Integer.toHexString( val >> 4 ) );
1143 buf.append( Integer.toHexString( val & 0xf ) );
1144 }
1145
1146 return buf.toString();
1147 }
1148
1149
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001150 public boolean isLogEnabled( int level )
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001151 {
1152 return level <= logLevel;
1153 }
1154
1155
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001156 public void log( int level, String format, Object[] args )
Felix Meschberger4f269292011-10-21 13:52:31 +00001157 {
1158 if ( isLogEnabled( level ) )
1159 {
1160 Throwable throwable = null;
1161 String message = format;
1162
1163 if ( args != null && args.length > 0 )
1164 {
1165 if ( args[args.length - 1] instanceof Throwable )
1166 {
1167 throwable = ( Throwable ) args[args.length - 1];
1168 }
1169 message = MessageFormat.format( format, args );
1170 }
1171
1172 log( level, message, throwable );
1173 }
1174 }
1175
1176
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001177 public void log( int level, String message, Throwable t )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001178 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001179 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +00001180 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001181 if ( log != null )
1182 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +00001183 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001184 return;
1185 }
1186
Felix Meschberger08282c32009-01-28 07:01:55 +00001187 // Otherwise only log if more serious than the configured level
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001188 if ( isLogEnabled( level ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001189 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001190 String code;
1191 switch ( level )
1192 {
1193 case LogService.LOG_INFO:
1194 code = "*INFO *";
1195 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001196
Felix Meschberger08282c32009-01-28 07:01:55 +00001197 case LogService.LOG_WARNING:
1198 code = "*WARN *";
1199 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001200
Felix Meschberger08282c32009-01-28 07:01:55 +00001201 case LogService.LOG_ERROR:
1202 code = "*ERROR*";
1203 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001204
Felix Meschberger08282c32009-01-28 07:01:55 +00001205 case LogService.LOG_DEBUG:
1206 default:
1207 code = "*DEBUG*";
1208 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001209
Felix Meschberger08282c32009-01-28 07:01:55 +00001210 System.err.println( code + " " + message );
1211 if ( t != null )
1212 {
1213 t.printStackTrace( System.err );
1214 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001215 }
1216 }
1217
Felix Meschberger851c6412009-08-16 18:43:26 +00001218
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001219 public static String toString( ServiceReference ref )
Felix Meschberger41cce522009-08-19 05:54:40 +00001220 {
1221 String[] ocs = ( String[] ) ref.getProperty( "objectClass" );
Felix Meschberger382a19b2012-07-03 09:45:14 +00001222 StringBuffer buf = new StringBuffer( "[" );
Felix Meschberger41cce522009-08-19 05:54:40 +00001223 for ( int i = 0; i < ocs.length; i++ )
1224 {
Felix Meschberger382a19b2012-07-03 09:45:14 +00001225 buf.append( ocs[i] );
Felix Meschberger41cce522009-08-19 05:54:40 +00001226 if ( i < ocs.length - 1 )
Felix Meschberger382a19b2012-07-03 09:45:14 +00001227 buf.append( ", " );
Felix Meschberger41cce522009-08-19 05:54:40 +00001228 }
1229
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001230 buf.append( ", id=" ).append( ref.getProperty( Constants.SERVICE_ID ) );
1231
1232 Bundle provider = ref.getBundle();
1233 if ( provider != null )
1234 {
1235 buf.append( ", bundle=" ).append( provider.getBundleId() );
Felix Meschberger0135b322011-11-16 12:30:22 +00001236 buf.append( '/' ).append( provider.getLocation() );
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001237 }
1238 else
1239 {
1240 buf.append( ", unregistered" );
1241 }
1242
1243 buf.append( "]" );
1244 return buf.toString();
Felix Meschberger41cce522009-08-19 05:54:40 +00001245 }
1246
Felix Meschbergerce67d732009-08-20 06:26:35 +00001247
Felix Meschberger007c50e2011-10-20 12:39:38 +00001248 /**
1249 * Checks whether the bundle is allowed to receive the configuration
1250 * with the given location binding.
1251 * <p>
1252 * This method implements the logic defined CM 1.4 / 104.4.1:
1253 * <ul>
1254 * <li>If the location is <code>null</code> (the configuration is not
1255 * bound yet), assume the bundle is allowed</li>
1256 * <li>If the location is a single location (no leading "?"), require
1257 * the bundle's location to match</li>
1258 * <li>If the location is a multi-location (leading "?"), assume the
1259 * bundle is allowed if there is no security manager. If there is a
1260 * security manager, check whether the bundle has "target" permission
1261 * on this location.</li>
1262 * </ul>
1263 */
1264 boolean canReceive( final Bundle bundle, final String location )
1265 {
1266 if ( location == null )
1267 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001268 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration=(unbound)", new Object[]
Felix Meschberger61207232011-11-17 10:06:45 +00001269 { bundle.getLocation() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001270 return true;
1271 }
1272 else if ( location.startsWith( "?" ) )
1273 {
1274 // multi-location
1275 if ( System.getSecurityManager() != null )
1276 {
Felix Meschberger61207232011-11-17 10:06:45 +00001277 final boolean hasPermission = bundle.hasPermission( new ConfigurationPermission( location,
1278 ConfigurationPermission.TARGET ) );
1279 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2} (SecurityManager check)",
1280 new Object[]
1281 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1282 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001283 }
Felix Meschberger61207232011-11-17 10:06:45 +00001284
1285 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration={1} (no SecurityManager)",
1286 new Object[]
1287 { bundle.getLocation(), location } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001288 return true;
1289 }
1290 else
1291 {
1292 // single location, must match
Felix Meschberger61207232011-11-17 10:06:45 +00001293 final boolean hasPermission = location.equals( bundle.getLocation() );
1294 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2}", new Object[]
1295 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1296 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001297 }
1298 }
1299
Felix Meschberger61207232011-11-17 10:06:45 +00001300
Felix Meschberger007c50e2011-10-20 12:39:38 +00001301 // ---------- inner classes
1302
Felix Meschberger007c50e2011-10-20 12:39:38 +00001303 /**
1304 * The <code>ManagedServiceUpdate</code> updates a freshly registered
1305 * <code>ManagedService</code> with a specific configuration. If a
1306 * ManagedService is registered with multiple PIDs an instance of this
1307 * class is used for each registered PID.
1308 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001309 private class ManagedServiceUpdate implements Runnable
1310 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001311 private final String pid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001312
Felix Meschberger41cce522009-08-19 05:54:40 +00001313 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001314
Felix Meschberger41cce522009-08-19 05:54:40 +00001315 private final ConfigurationImpl config;
1316
1317 private final Dictionary rawProperties;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001318
Felix Meschberger61207232011-11-17 10:06:45 +00001319 private final long revision;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001320
Felix Meschberger382a19b2012-07-03 09:45:14 +00001321 ManagedServiceUpdate( String pid, ServiceReference sr )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001322 {
1323 this.pid = pid;
1324 this.sr = sr;
Felix Meschberger41cce522009-08-19 05:54:40 +00001325
1326 // get or load configuration for the pid
1327 ConfigurationImpl config = null;
1328 Dictionary rawProperties = null;
Felix Meschberger61207232011-11-17 10:06:45 +00001329 long revision = -1;
Felix Meschberger41cce522009-08-19 05:54:40 +00001330 try
1331 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001332 config = getTargetedConfiguration( pid, sr );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001333 if ( config != null )
1334 {
1335 synchronized ( config )
1336 {
1337 rawProperties = config.getProperties( true );
Felix Meschberger61207232011-11-17 10:06:45 +00001338 revision = config.getRevision();
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001339 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001340 }
1341 }
1342 catch ( IOException ioe )
1343 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001344 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1345 { pid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001346 }
1347
1348 this.config = config;
1349 this.rawProperties = rawProperties;
Felix Meschberger61207232011-11-17 10:06:45 +00001350 this.revision = revision;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001351 }
1352
1353
1354 public void run()
1355 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001356 Dictionary properties = rawProperties;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001357
1358 // check configuration and call plugins if existing
Felix Meschberger41cce522009-08-19 05:54:40 +00001359 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001360 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001361 log( LogService.LOG_DEBUG, "Updating service {0} to with configuration {1}@{2}", new Object[]
1362 { pid, this.config.getPid(), new Long( revision ) } );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001363
Felix Meschberger41243192009-01-14 19:59:58 +00001364 Bundle serviceBundle = sr.getBundle();
1365 if ( serviceBundle == null )
1366 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001367 log( LogService.LOG_INFO,
1368 "Service for PID {0} seems to already have been unregistered, not updating with configuration",
1369 new Object[]
1370 { pid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001371 return;
1372 }
1373
Felix Meschberger27689c12011-11-16 08:52:04 +00001374 if ( canReceive( serviceBundle, config.getBundleLocation() ) )
Felix Meschberger2941ef92007-08-20 13:15:16 +00001375 {
Felix Meschberger27689c12011-11-16 08:52:04 +00001376 // 104.4.2 Dynamic Binding
1377 config.tryBindLocation( serviceBundle.getLocation() );
Felix Meschberger27689c12011-11-16 08:52:04 +00001378 }
1379 else
1380 {
1381 // CM 1.4 / 104.13.2.2 / 104.5.3
1382 // act as if there is no configuration
1383 log(
1384 LogService.LOG_DEBUG,
1385 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}; calling with null",
Felix Meschberger4f269292011-10-21 13:52:31 +00001386 new Object[]
1387 { pid, ConfigurationManager.toString( sr ), config.getBundleLocation() } );
Felix Meschberger27689c12011-11-16 08:52:04 +00001388
1389 // CM 1.4 / 104.5.3 ManagedService.updated must be
1390 // called with null if configuration is no visible
1391 properties = null;
Felix Meschberger2941ef92007-08-20 13:15:16 +00001392 }
1393
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001394 }
1395 else
1396 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001397 // 104.5.3 ManagedService.updated must be called with null
1398 // if no configuration is available
Felix Meschberger41cce522009-08-19 05:54:40 +00001399 properties = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001400 }
1401
Felix Meschberger382a19b2012-07-03 09:45:14 +00001402 managedServiceTracker.provideConfiguration( sr, config, properties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001403 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001404
Felix Meschberger432e3872008-03-07 14:58:57 +00001405 public String toString()
1406 {
1407 return "ManagedService Update: pid=" + pid;
1408 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001409 }
1410
Felix Meschberger007c50e2011-10-20 12:39:38 +00001411 /**
1412 * The <code>ManagedServiceFactoryUpdate</code> updates a freshly
1413 * registered <code>ManagedServiceFactory</code> with a specific
1414 * configuration. If a ManagedServiceFactory is registered with
1415 * multiple PIDs an instance of this class is used for each registered
1416 * PID.
1417 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001418 private class ManagedServiceFactoryUpdate implements Runnable
1419 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001420 private final String factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001421
Felix Meschberger41cce522009-08-19 05:54:40 +00001422 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001423
Felix Meschberger41cce522009-08-19 05:54:40 +00001424 private final Map configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001425
Felix Meschberger61207232011-11-17 10:06:45 +00001426 private final Map revisions;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001427
Felix Meschberger382a19b2012-07-03 09:45:14 +00001428 ManagedServiceFactoryUpdate( String factoryPid, ServiceReference sr )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001429 {
1430 this.factoryPid = factoryPid;
1431 this.sr = sr;
Felix Meschberger41cce522009-08-19 05:54:40 +00001432
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001433 List<Factory> factories = null;
Felix Meschberger41cce522009-08-19 05:54:40 +00001434 Map configs = null;
Felix Meschberger61207232011-11-17 10:06:45 +00001435 Map revisions = null;
Felix Meschberger41cce522009-08-19 05:54:40 +00001436 try
1437 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001438 factories = getTargetedFactories( factoryPid, sr );
1439 for (Factory factory : factories) {
Felix Meschberger41cce522009-08-19 05:54:40 +00001440 configs = new HashMap();
Felix Meschberger61207232011-11-17 10:06:45 +00001441 revisions = new HashMap();
Felix Meschberger41cce522009-08-19 05:54:40 +00001442 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
1443 {
1444 final String pid = ( String ) pi.next();
1445 ConfigurationImpl cfg;
1446 try
1447 {
Felix Meschbergerad949872011-11-16 10:34:54 +00001448 cfg = getConfiguration( pid );
Felix Meschberger41cce522009-08-19 05:54:40 +00001449 }
1450 catch ( IOException ioe )
1451 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001452 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1453 { pid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001454 continue;
1455 }
1456
1457 // sanity check on the configuration
1458 if ( cfg == null )
1459 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001460 log( LogService.LOG_ERROR, "Configuration {0} referred to by factory {1} does not exist",
1461 new Object[]
1462 { pid, factoryPid } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001463 factory.removePID( pid );
1464 factory.storeSilently();
1465 continue;
1466 }
1467 else if ( cfg.isNew() )
1468 {
1469 // Configuration has just been created but not yet updated
1470 // we currently just ignore it and have the update mechanism
1471 // provide the configuration to the ManagedServiceFactory
1472 // As of FELIX-612 (not storing new factory configurations)
1473 // this should not happen. We keep this for added stability
1474 // but raise the logging level to error.
Felix Meschberger4f269292011-10-21 13:52:31 +00001475 log( LogService.LOG_ERROR, "Ignoring new configuration pid={0}", new Object[]
1476 { pid } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001477 continue;
1478 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001479 /*
1480 * this code would catch targeted factory PIDs;
1481 * since this is not expected any way, we can
1482 * leave this out
1483 */
1484 /*
Felix Meschberger41cce522009-08-19 05:54:40 +00001485 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1486 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001487 log( LogService.LOG_ERROR,
1488 "Configuration {0} referred to by factory {1} seems to belong to factory {2}",
1489 new Object[]
1490 { pid, factoryPid, cfg.getFactoryPid() } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001491 factory.removePID( pid );
1492 factory.storeSilently();
1493 continue;
1494 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001495 */
Felix Meschberger41cce522009-08-19 05:54:40 +00001496
1497 // get the configuration properties for later
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001498 synchronized ( cfg )
1499 {
1500 configs.put( cfg, cfg.getProperties( true ) );
Felix Meschberger61207232011-11-17 10:06:45 +00001501 revisions.put( cfg, new Long( cfg.getRevision() ) );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001502 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001503 }
1504 }
1505 }
1506 catch ( IOException ioe )
1507 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001508 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID {0}", new Object[]
1509 { factoryPid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001510 }
1511
Felix Meschberger41cce522009-08-19 05:54:40 +00001512 this.configs = configs;
Felix Meschberger61207232011-11-17 10:06:45 +00001513 this.revisions = revisions;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001514 }
1515
1516
1517 public void run()
1518 {
Felix Meschberger41243192009-01-14 19:59:58 +00001519 Bundle serviceBundle = sr.getBundle();
1520 if ( serviceBundle == null )
1521 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001522 log(
1523 LogService.LOG_INFO,
1524 "ManagedServiceFactory for factory PID {0} seems to already have been unregistered, not updating with factory",
1525 new Object[]
1526 { factoryPid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001527 return;
1528 }
1529
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001530 if ( configs == null || configs.isEmpty() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001531 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001532 log( LogService.LOG_DEBUG, "No configuration with factory PID {0}; not updating ManagedServiceFactory",
1533 new Object[]
1534 { factoryPid } );
1535 }
1536 else
1537 {
1538 for ( Iterator ci = configs.entrySet().iterator(); ci.hasNext(); )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001539 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001540 final Map.Entry entry = ( Map.Entry ) ci.next();
1541 final ConfigurationImpl cfg = ( ConfigurationImpl ) entry.getKey();
1542 final Dictionary properties = ( Dictionary ) entry.getValue();
1543 final long revision = ( ( Long ) revisions.get( cfg ) ).longValue();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001544
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001545 log( LogService.LOG_DEBUG, "Updating service {0} with configuration {1}/{2}@{3}", new Object[]
1546 { this.factoryPid, cfg.getFactoryPid(), cfg.getPid(), new Long( revision ) } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001547
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001548 // CM 1.4 / 104.13.2.1
1549 if ( !canReceive( serviceBundle, cfg.getBundleLocation() ) )
Felix Meschberger2941ef92007-08-20 13:15:16 +00001550 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001551 log( LogService.LOG_ERROR,
1552 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1553 new Object[]
1554 { cfg.getPid(), ConfigurationManager.toString( sr ), cfg.getBundleLocation() } );
1555 continue;
Felix Meschberger2941ef92007-08-20 13:15:16 +00001556 }
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001557
1558 // 104.4.2 Dynamic Binding
1559 cfg.tryBindLocation( serviceBundle.getLocation() );
1560
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001561 // update the service with the configuration (if non-null)
1562 if ( properties != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001563 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001564 log( LogService.LOG_DEBUG, "{0}: Updating configuration pid={1}", new Object[]
1565 { ConfigurationManager.toString( sr ), cfg.getPid() } );
Felix Meschberger382a19b2012-07-03 09:45:14 +00001566 managedServiceFactoryTracker.provideConfiguration( sr, cfg, properties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001567 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001568 }
1569 }
1570 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001571
1572
Felix Meschberger432e3872008-03-07 14:58:57 +00001573 public String toString()
1574 {
1575 return "ManagedServiceFactory Update: factoryPid=" + factoryPid;
1576 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001577 }
1578
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001579 private abstract class ConfigurationProvider<T> implements Runnable
1580 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001581
1582 protected final ConfigurationImpl config;
1583 protected final long revision;
1584 protected final Dictionary<String, ?> properties;
1585 protected final BaseTracker<T> helper;
1586
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001587
1588 protected ConfigurationProvider( final ConfigurationImpl config )
1589 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001590 synchronized ( config )
1591 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001592 this.config = config;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001593 this.revision = config.getRevision();
1594 this.properties = config.getProperties( true );
1595 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001596 this.helper = ( BaseTracker<T> ) ( ( config.getFactoryPid() == null ) ? managedServiceTracker
1597 : managedServiceFactoryTracker );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001598 }
1599
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001600
1601 protected TargetedPID getTargetedServicePid()
1602 {
1603 final TargetedPID factoryPid = this.config.getFactoryPid();
1604 if ( factoryPid != null )
1605 {
1606 return factoryPid;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001607 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001608 return this.config.getPid();
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001609 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001610 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001611
1612 /**
1613 * The <code>UpdateConfiguration</code> is used to update
1614 * <code>ManagedService[Factory]</code> services with the configuration
1615 * they are subscribed to. This may cause the configuration to be
1616 * supplied to multiple services.
1617 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001618 private class UpdateConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001619 {
1620
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001621 UpdateConfiguration( final ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001622 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001623 super( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001624 }
1625
1626
1627 public void run()
1628 {
Felix Meschberger61207232011-11-17 10:06:45 +00001629 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1630 { config.getPid(), new Long( revision ) } );
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001631
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001632 final List<ServiceReference<?>> srList = this.helper.getServices( getTargetedServicePid() );
1633 if ( !srList.isEmpty() )
Felix Meschberger41cce522009-08-19 05:54:40 +00001634 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001635 // optionally bind dynamically to the first service
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001636 config.tryBindLocation( srList.get( 0 ).getBundle().getLocation() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001637
1638 final String configBundleLocation = config.getBundleLocation();
1639
1640 // provide configuration to all services from the
1641 // correct bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001642 for (ServiceReference<?> ref : srList)
Felix Meschberger41cce522009-08-19 05:54:40 +00001643 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001644 final Bundle refBundle = ref.getBundle();
1645 if ( refBundle == null )
Felix Meschberger41cce522009-08-19 05:54:40 +00001646 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001647 log( LogService.LOG_DEBUG,
1648 "Service {0} seems to be unregistered concurrently (not providing configuration)",
1649 new Object[]
1650 { ConfigurationManager.toString( ref ) } );
1651 }
1652 else if ( canReceive( refBundle, configBundleLocation ) )
1653 {
Felix Meschbergeraccd9012012-07-02 15:18:08 +00001654 helper.provideConfiguration( ref, this.config, this.properties );
Felix Meschberger2444da62011-11-17 11:17:50 +00001655 }
1656 else
1657 {
1658 // CM 1.4 / 104.13.2.2
Felix Meschberger4f269292011-10-21 13:52:31 +00001659 log( LogService.LOG_ERROR,
1660 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1661 new Object[]
1662 { config.getPid(), ConfigurationManager.toString( ref ), configBundleLocation } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001663 }
1664
Felix Meschberger41cce522009-08-19 05:54:40 +00001665 }
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001666 }
Felix Meschberger137ee722011-11-16 09:51:59 +00001667 else if ( isLogEnabled( LogService.LOG_DEBUG ) )
1668 {
Felix Meschberger1ee888d2011-11-16 12:42:57 +00001669 log( LogService.LOG_DEBUG, "No ManagedService[Factory] registered for updates to configuration {0}",
Felix Meschberger137ee722011-11-16 09:51:59 +00001670 new Object[]
1671 { config.getPid() } );
1672 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001673 }
1674
1675
Felix Meschberger432e3872008-03-07 14:58:57 +00001676 public String toString()
1677 {
1678 return "Update: pid=" + config.getPid();
1679 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001680 }
1681
Felix Meschberger007c50e2011-10-20 12:39:38 +00001682
1683 /**
1684 * The <code>DeleteConfiguration</code> class is used to inform
1685 * <code>ManagedService[Factory]</code> services of a configuration
1686 * being deleted.
1687 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001688 private class DeleteConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001689 {
Felix Meschberger66423332007-08-22 08:46:34 +00001690
Felix Meschbergerc12db8c2009-08-19 06:43:59 +00001691 private final String configLocation;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001692
1693
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001694 DeleteConfiguration( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001695 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001696 /*
1697 * NOTE: We keep the configuration because it might be cleared just
1698 * after calling this method. The pid and factoryPid fields are
1699 * final and cannot be reset.
1700 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001701 super(config);
Felix Meschberger007c50e2011-10-20 12:39:38 +00001702 this.configLocation = config.getBundleLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001703 }
1704
1705
1706 public void run()
1707 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001708 List<ServiceReference<?>> srList = this.helper.getServices( getTargetedServicePid() );
1709 if ( !srList.isEmpty() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001710 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001711 for (ServiceReference<?> sr : srList)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001712 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001713 final Bundle srBundle = sr.getBundle();
1714 if ( srBundle == null )
1715 {
1716 log( LogService.LOG_DEBUG,
1717 "Service {0} seems to be unregistered concurrently (not removing configuration)",
1718 new Object[]
1719 { ConfigurationManager.toString( sr ) } );
1720 }
1721 else if ( canReceive( srBundle, configLocation ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001722 {
Felix Meschbergeraccd9012012-07-02 15:18:08 +00001723 this.helper.removeConfiguration( sr, this.config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001724 }
Felix Meschberger2444da62011-11-17 11:17:50 +00001725 else
1726 {
1727 // CM 1.4 / 104.13.2.2
1728 log( LogService.LOG_ERROR,
1729 "Cannot remove configuration {0} for {1}: No visibility to configuration bound to {2}",
1730 new Object[]
1731 { config.getPid(), ConfigurationManager.toString( sr ), configLocation } );
1732 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001733 }
1734 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001735
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001736 final TargetedPID factoryPid = config.getFactoryPid();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001737 if ( factoryPid != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001738 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001739 // remove the pid from the factory
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001740 final String pid = config.getPidString();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001741 try
1742 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001743 Factory factory = getOrCreateFactory( factoryPid.toString() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001744 factory.removePID( pid );
1745 factory.store();
1746 }
1747 catch ( IOException ioe )
1748 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001749 log( LogService.LOG_ERROR, "Failed removing {0} from the factory {1}", new Object[]
1750 { pid, factoryPid, ioe } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001751 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001752 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001753 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001754
Felix Meschberger432e3872008-03-07 14:58:57 +00001755 public String toString()
1756 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001757 return "Delete: pid=" + config.getPid();
Felix Meschberger432e3872008-03-07 14:58:57 +00001758 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001759 }
1760
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001761 private class LocationChanged extends ConfigurationProvider
Felix Meschberger007c50e2011-10-20 12:39:38 +00001762 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001763 private final String oldLocation;
1764
1765
1766 LocationChanged( ConfigurationImpl config, String oldLocation )
1767 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001768 super( config );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001769 this.oldLocation = oldLocation;
1770 }
1771
1772
1773 public void run()
1774 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001775 List<ServiceReference<?>> srList = helper.getServices( getTargetedServicePid() );
1776 if ( !srList.isEmpty() )
Felix Meschberger007c50e2011-10-20 12:39:38 +00001777 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001778 for (final ServiceReference<?> sr : srList)
Felix Meschberger007c50e2011-10-20 12:39:38 +00001779 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001780 final Bundle srBundle = sr.getBundle();
1781 if ( srBundle == null )
1782 {
1783 log( LogService.LOG_DEBUG,
1784 "Service {0} seems to be unregistered concurrently (not processing)", new Object[]
1785 { ConfigurationManager.toString( sr ) } );
1786 continue;
1787 }
1788
1789 final boolean wasVisible = canReceive( srBundle, oldLocation );
1790 final boolean isVisible = canReceive( srBundle, config.getBundleLocation() );
1791
1792 // make sure the config is dynamically bound to the first
1793 // service if the config has been unbound causing this update
1794 if ( isVisible )
1795 {
1796 config.tryBindLocation( srBundle.getLocation() );
1797 }
1798
Felix Meschberger007c50e2011-10-20 12:39:38 +00001799 if ( wasVisible && !isVisible )
1800 {
1801 // call deleted method
Felix Meschbergeraccd9012012-07-02 15:18:08 +00001802 helper.removeConfiguration( sr, this.config );
Felix Meschberger4f269292011-10-21 13:52:31 +00001803 log( LogService.LOG_DEBUG, "Configuration {0} revoked from {1} (no more visibility)",
1804 new Object[]
1805 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001806 }
1807 else if ( !wasVisible && isVisible )
1808 {
1809 // call updated method
Felix Meschbergeraccd9012012-07-02 15:18:08 +00001810 helper.provideConfiguration( sr, this.config, this.properties );
Felix Meschberger4f269292011-10-21 13:52:31 +00001811 log( LogService.LOG_DEBUG, "Configuration {0} provided to {1} (new visibility)", new Object[]
1812 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger35658d52011-10-20 21:43:58 +00001813 }
Felix Meschberger4f269292011-10-21 13:52:31 +00001814 else
Felix Meschberger35658d52011-10-20 21:43:58 +00001815 {
1816 // same visibility as before
Felix Meschberger4f269292011-10-21 13:52:31 +00001817 log( LogService.LOG_DEBUG, "Unmodified visibility to configuration {0} for {1}", new Object[]
1818 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001819 }
1820 }
1821 }
1822 }
1823
1824
1825 public String toString()
1826 {
1827 return "Location Changed (pid=" + config.getPid() + "): " + oldLocation + " ==> "
1828 + config.getBundleLocation();
1829 }
1830 }
1831
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001832 private class FireConfigurationEvent implements Runnable
1833 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001834 private final int type;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001835
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001836 private final String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001837
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001838 private final String factoryPid;
1839
1840 private final ServiceReference[] listenerReferences;
1841
1842 private final ConfigurationListener[] listeners;
1843
1844 private final Bundle[] listenerProvider;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001845
Felix Meschberger0770cad2012-06-11 12:36:52 +00001846 private ConfigurationEvent event;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001847
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001848 private FireConfigurationEvent( final int type, final String pid, final String factoryPid)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001849 {
1850 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001851 this.pid = pid;
1852 this.factoryPid = factoryPid;
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001853
1854 final ServiceReference[] srs = configurationListenerTracker.getServiceReferences();
1855 if ( srs == null || srs.length == 0 )
1856 {
1857 this.listenerReferences = null;
1858 this.listeners = null;
1859 this.listenerProvider = null;
1860 }
1861 else
1862 {
1863 this.listenerReferences = srs;
1864 this.listeners = new ConfigurationListener[srs.length];
1865 this.listenerProvider = new Bundle[srs.length];
1866 for ( int i = 0; i < srs.length; i++ )
1867 {
1868 this.listeners[i] = ( ConfigurationListener ) configurationListenerTracker.getService( srs[i] );
1869 this.listenerProvider[i] = srs[i].getBundle();
1870 }
1871 }
1872 }
1873
1874
Felix Meschberger0770cad2012-06-11 12:36:52 +00001875 void fireSynchronousEvents()
1876 {
1877 if ( hasConfigurationEventListeners() && getServiceReference() != null )
1878 {
1879 for ( int i = 0; i < this.listeners.length; i++ )
1880 {
1881 if ( this.listeners[i] instanceof SynchronousConfigurationListener )
1882 {
1883 sendEvent( i );
1884 }
1885 }
1886 }
1887 }
1888
1889
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001890 boolean hasConfigurationEventListeners()
1891 {
1892 return this.listenerReferences != null;
1893 }
1894
1895
1896 String getTypeName()
1897 {
1898 switch ( type )
1899 {
1900 case ConfigurationEvent.CM_DELETED:
1901 return "CM_DELETED";
1902 case ConfigurationEvent.CM_UPDATED:
1903 return "CM_UPDATED";
Felix Meschberger007c50e2011-10-20 12:39:38 +00001904 case ConfigurationEvent.CM_LOCATION_CHANGED:
1905 return "CM_LOCATION_CHANGED";
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001906 default:
1907 return "<UNKNOWN(" + type + ")>";
1908 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001909 }
1910
1911
1912 public void run()
1913 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001914 for ( int i = 0; i < listeners.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001915 {
Felix Meschberger0770cad2012-06-11 12:36:52 +00001916 sendEvent( i );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001917 }
1918 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001919
Felix Meschberger0770cad2012-06-11 12:36:52 +00001920
Felix Meschberger432e3872008-03-07 14:58:57 +00001921 public String toString()
1922 {
1923 return "Fire ConfigurationEvent: pid=" + pid;
1924 }
Felix Meschberger0770cad2012-06-11 12:36:52 +00001925
1926
1927 private ConfigurationEvent getConfigurationEvent()
1928 {
1929 if ( event == null )
1930 {
1931 this.event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
1932 }
1933 return event;
1934 }
1935
1936
1937 private void sendEvent( final int serviceIndex )
1938 {
1939 if ( listenerProvider[serviceIndex].getState() == Bundle.ACTIVE && this.listeners[serviceIndex] != null )
1940 {
1941 log( LogService.LOG_DEBUG, "Sending {0} event for {1} to {2}", new Object[]
1942 { getTypeName(), pid, ConfigurationManager.toString( listenerReferences[serviceIndex] ) } );
1943
1944 try
1945 {
1946 listeners[serviceIndex].configurationEvent( getConfigurationEvent() );
1947 }
1948 catch ( Throwable t )
1949 {
1950 log( LogService.LOG_ERROR, "Unexpected problem delivering configuration event to {0}", new Object[]
1951 { ConfigurationManager.toString( listenerReferences[serviceIndex] ), t } );
1952 }
1953 finally
1954 {
1955 this.listeners[serviceIndex] = null;
1956 }
1957 }
1958 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001959 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001960}