blob: b36b01474b5d06df690aae30febf349891891756 [file] [log] [blame]
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001/*
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.apache.felix.cm.impl;
20
21
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000022import java.io.IOException;
23import java.security.SecureRandom;
Felix Meschberger4f269292011-10-21 13:52:31 +000024import java.text.MessageFormat;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000025import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.Dictionary;
28import java.util.Enumeration;
29import java.util.HashMap;
30import java.util.Hashtable;
31import java.util.Iterator;
32import java.util.List;
33import java.util.Map;
34import java.util.Random;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000035
36import org.apache.felix.cm.PersistenceManager;
37import org.apache.felix.cm.file.FilePersistenceManager;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000038import org.apache.felix.cm.impl.helper.BaseTracker;
39import org.apache.felix.cm.impl.helper.ManagedServiceFactoryTracker;
40import org.apache.felix.cm.impl.helper.ManagedServiceTracker;
41import org.apache.felix.cm.impl.helper.TargetedPID;
42import org.osgi.framework.Bundle;
43import org.osgi.framework.BundleActivator;
44import org.osgi.framework.BundleContext;
45import org.osgi.framework.BundleEvent;
46import org.osgi.framework.BundleListener;
47import org.osgi.framework.Constants;
48import org.osgi.framework.Filter;
49import org.osgi.framework.InvalidSyntaxException;
50import org.osgi.framework.ServiceReference;
51import org.osgi.framework.ServiceRegistration;
52import org.osgi.service.cm.ConfigurationAdmin;
53import org.osgi.service.cm.ConfigurationEvent;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000054import org.osgi.service.cm.ConfigurationListener;
55import org.osgi.service.cm.ConfigurationPermission;
56import org.osgi.service.cm.ConfigurationPlugin;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000057import org.osgi.service.cm.SynchronousConfigurationListener;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000058import org.osgi.service.log.LogService;
59import org.osgi.util.tracker.ServiceTracker;
60
61
62/**
63 * The <code>ConfigurationManager</code> is the central class in this
64 * implementation of the Configuration Admin Service Specification. As such it
65 * has the following tasks:
66 * <ul>
67 * <li>It is a <code>BundleActivator</code> which is called when the bundle
68 * is started and stopped.
69 * <li>It is a <code>BundleListener</code> which gets informed when the
70 * states of bundles change. Mostly this is needed to unbind any bound
71 * configuration in case a bundle is uninstalled.
72 * <li>It is a <code>ServiceListener</code> which gets informed when
73 * <code>ManagedService</code> and <code>ManagedServiceFactory</code>
74 * services are registered and unregistered. This is used to provide
75 * configuration to these services. As a service listener it also listens for
76 * {@link PersistenceManager} instances being registered to support different
77 * configuration persistence layers.
78 * <li>A {@link ConfigurationAdminFactory} instance is registered as the
79 * <code>ConfigurationAdmin</code> service.
80 * <li>A {@link FilePersistenceManager} instance is registered as a default
81 * {@link PersistenceManager}.
82 * <li>Last but not least this instance manages all tasks laid out in the
83 * specification such as maintaining configuration, taking care of configuration
84 * events, etc.
85 * </ul>
86 * <p>
87 * The default {@link FilePersistenceManager} is configured with a configuration
88 * location taken from the <code>felix.cm.dir</code> framework property. If
89 * this property is not set the <code>config</code> directory in the current
90 * working directory as specified in the <code>user.dir</code> system property
91 * is used.
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000092 */
93public class ConfigurationManager implements BundleActivator, BundleListener
94{
95
96 /**
97 * The name of the bundle context property defining the location for the
98 * configuration files (value is "felix.cm.dir").
Felix Meschberger2fd5b582007-12-10 10:32:29 +000099 *
Carsten Ziegeler7853b9a2008-01-11 16:30:24 +0000100 * @see #start(BundleContext)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000101 */
102 public static final String CM_CONFIG_DIR = "felix.cm.dir";
103
Felix Meschberger08282c32009-01-28 07:01:55 +0000104 /**
105 * The name of the bundle context property defining the maximum log level
106 * (value is "felix.cm.loglevel"). The log level setting is only used if
107 * there is no OSGi LogService available. Otherwise this setting is ignored.
108 * <p>
109 * This value of this property is expected to be an integer number
110 * corresponding to the log level values of the OSGi LogService. That is 1
111 * for errors, 2 for warnings, 3 for informational messages and 4 for debug
112 * messages. The default value is 2, such that only warnings and errors are
113 * logged in the absence of a LogService.
114 */
115 public static final String CM_LOG_LEVEL = "felix.cm.loglevel";
116
Felix Meschberger85b355d2007-08-31 07:17:38 +0000117 // The name of the LogService (not using the class, which might be missing)
118 private static final String LOG_SERVICE_NAME = "org.osgi.service.log.LogService";
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000119
Felix Meschberger08282c32009-01-28 07:01:55 +0000120 private static final int CM_LOG_LEVEL_DEFAULT = 2;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000121
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000122 // random number generator to create configuration PIDs for factory
123 // configurations
Felix Meschberger417f66c2011-02-04 11:25:23 +0000124 private static Random numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000125
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000126 // the BundleContext of the Configuration Admin Service bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000127 BundleContext bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000128
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000129 // the service registration of the configuration admin
Felix Meschberger4b26df92011-02-01 12:41:45 +0000130 private volatile ServiceRegistration configurationAdminRegistration;
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000131
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000132 // the ServiceTracker to emit log services (see log(int, String, Throwable))
133 private ServiceTracker logTracker;
134
135 // the ConfigurationEvent listeners
136 private ServiceTracker configurationListenerTracker;
137
138 // service tracker for managed services
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000139 private ManagedServiceTracker managedServiceTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000140
141 // service tracker for managed service factories
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000142 private ManagedServiceFactoryTracker managedServiceFactoryTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000143
144 // PersistenceManager services
145 private ServiceTracker persistenceManagerTracker;
146
147 // the thread used to schedule tasks required to run asynchronously
148 private UpdateThread updateThread;
149
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000150 // the thread used to schedule events to be dispatched asynchronously
151 private UpdateThread eventThread;
152
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000153 /**
154 * The actual list of {@link PersistenceManager persistence managers} to use
155 * when looking for configuration data. This list is built from the
156 * {@link #persistenceManagerMap}, which is ordered according to the
157 * {@link RankingComparator}.
158 */
159 private PersistenceManager[] persistenceManagers;
160
161 // the persistenceManagerTracker.getTrackingCount when the
162 // persistenceManagers were last got
163 private int pmtCount;
164
165 // the cache of Factory instances mapped by their factory PID
Felix Meschberger6a698df2009-08-16 18:38:46 +0000166 private final Map factories = new HashMap();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000167
168 // the cache of Configuration instances mapped by their PID
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000169 // have this always set to prevent NPE on bundle shutdown
170 private final Map configurations = new HashMap();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000171
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000172 /**
173 * The map of dynamic configuration bindings. This maps the
174 * PID of the dynamically bound configuration or factory to its bundle
175 * location.
176 * <p>
177 * On bundle startup this map is loaded from persistence and validated
178 * against the locations of installed bundles: Entries pointing to bundle
179 * locations not currently installed are removed.
180 * <p>
181 * The map is written to persistence on each change.
182 */
183 private DynamicBindings dynamicBindings;
184
Felix Meschberger08282c32009-01-28 07:01:55 +0000185 // the maximum log level when no LogService is available
186 private int logLevel = CM_LOG_LEVEL_DEFAULT;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000187
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000188 // flag indicating whether BundleChange events should be consumed (FELIX-979)
189 private volatile boolean handleBundleEvents;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000190
Felix Meschberger623f7142012-01-31 07:13:37 +0000191 // flag indicating whether the manager is considered alive
192 private volatile boolean isActive;
193
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000194 public void start( BundleContext bundleContext )
195 {
196 // track the log service using a ServiceTracker
Felix Meschberger85b355d2007-08-31 07:17:38 +0000197 logTracker = new ServiceTracker( bundleContext, LOG_SERVICE_NAME , null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000198 logTracker.open();
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000199
Felix Meschberger08282c32009-01-28 07:01:55 +0000200 // assign the log level
201 String logLevelProp = bundleContext.getProperty( CM_LOG_LEVEL );
202 if ( logLevelProp == null )
203 {
204 logLevel = CM_LOG_LEVEL_DEFAULT;
205 }
206 else
207 {
208 try
209 {
210 logLevel = Integer.parseInt( logLevelProp );
211 }
212 catch ( NumberFormatException nfe )
213 {
214 logLevel = CM_LOG_LEVEL_DEFAULT;
215 }
216 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000217
218 // set up some fields
219 this.bundleContext = bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000220
221 // configurationlistener support
222 configurationListenerTracker = new ServiceTracker( bundleContext, ConfigurationListener.class.getName(), null );
223 configurationListenerTracker.open();
224
225 // initialize the asynchonous updater thread
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000226 ThreadGroup tg = new ThreadGroup( "Configuration Admin Service" );
227 tg.setDaemon( true );
228 this.updateThread = new UpdateThread( this, tg, "CM Configuration Updater" );
229 this.eventThread = new UpdateThread( this, tg, "CM Event Dispatcher" );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000230
231 // set up the location (might throw IllegalArgumentException)
232 try
233 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000234 FilePersistenceManager fpm = new FilePersistenceManager( bundleContext, bundleContext
235 .getProperty( CM_CONFIG_DIR ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000236 Hashtable props = new Hashtable();
237 props.put( Constants.SERVICE_PID, fpm.getClass().getName() );
238 props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
239 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
240 props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
241 bundleContext.registerService( PersistenceManager.class.getName(), fpm, props );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000242
243 // setup dynamic configuration bindings
244 dynamicBindings = new DynamicBindings( bundleContext, fpm );
245 }
246 catch ( IOException ioe )
247 {
248 log( LogService.LOG_ERROR, "Failure setting up dynamic configuration bindings", ioe );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000249 }
250 catch ( IllegalArgumentException iae )
251 {
252 log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
253 }
254
255 // register as bundle and service listener
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000256 handleBundleEvents = true;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000257 bundleContext.addBundleListener( this );
258
259 // get all persistence managers to begin with
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000260 pmtCount = 1; // make sure to get the persistence managers at least once
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000261 persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
262 persistenceManagerTracker.open();
263
Felix Meschberger623f7142012-01-31 07:13:37 +0000264 // consider alive now (before clients use Configuration Admin
265 // service registered in the next step)
266 isActive = true;
267
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000268 // create and register configuration admin - start after PM tracker ...
269 ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
270 Hashtable props = new Hashtable();
271 props.put( Constants.SERVICE_PID, "org.apache.felix.cm.ConfigurationAdmin" );
272 props.put( Constants.SERVICE_DESCRIPTION, "Configuration Admin Service Specification 1.2 Implementation" );
273 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000274 configurationAdminRegistration = bundleContext.registerService( ConfigurationAdmin.class.getName(), caf, props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000275
Felix Meschberger4b26df92011-02-01 12:41:45 +0000276 // start processing the event queues only after registering the service
277 // see FELIX-2813 for details
278 this.updateThread.start();
279 this.eventThread.start();
280
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000281 // start handling ManagedService[Factory] services
Carsten Ziegeler41683982007-12-27 08:35:27 +0000282 managedServiceTracker = new ManagedServiceTracker(this);
283 managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this);
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000284 }
285
286
287 public void stop( BundleContext bundleContext )
288 {
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000289
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000290 // stop handling bundle events immediately
291 handleBundleEvents = false;
292
Felix Meschberger4b26df92011-02-01 12:41:45 +0000293 // stop queue processing before unregistering the service
294 // see FELIX-2813 for details
295 if ( updateThread != null )
296 {
297 updateThread.terminate();
298 }
299 if ( eventThread != null )
300 {
301 eventThread.terminate();
302 }
303
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000304 // immediately unregister the Configuration Admin before cleaning up
Felix Meschberger10568352009-01-15 08:57:11 +0000305 // clearing the field before actually unregistering the service
306 // prevents IllegalStateException in getServiceReference() if
307 // the field is not null but the service already unregistered
308 if (configurationAdminRegistration != null) {
309 ServiceRegistration reg = configurationAdminRegistration;
310 configurationAdminRegistration = null;
311 reg.unregister();
312 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000313
Felix Meschberger623f7142012-01-31 07:13:37 +0000314 // consider inactive after unregistering such that during
315 // unregistration the manager is still alive and can react
316 isActive = false;
317
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000318 // stop handling ManagedService[Factory] services
319 managedServiceFactoryTracker.close();
320 managedServiceTracker.close();
321
322 // don't care for PersistenceManagers any more
323 persistenceManagerTracker.close();
324
325 // stop listening for events
326 bundleContext.removeBundleListener( this );
327
328 if ( configurationListenerTracker != null )
329 {
330 configurationListenerTracker.close();
331 }
332
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000333 if ( logTracker != null )
334 {
335 logTracker.close();
336 }
337
Felix Meschberger6a698df2009-08-16 18:38:46 +0000338 // just ensure the configuration cache is empty
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000339 synchronized ( configurations )
340 {
341 configurations.clear();
342 }
343
Felix Meschberger6a698df2009-08-16 18:38:46 +0000344 // just ensure the factory cache is empty
345 synchronized ( factories )
346 {
347 factories.clear();
348 }
349
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000350 this.bundleContext = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000351 }
352
353
Felix Meschberger623f7142012-01-31 07:13:37 +0000354 /**
355 * Returns <code>true</code> if this manager is considered active.
356 */
357 boolean isActive()
358 {
359 return isActive;
360 }
361
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000362 public BundleContext getBundleContext()
363 {
364 return bundleContext;
365 }
Felix Meschberger623f7142012-01-31 07:13:37 +0000366
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000367 // ---------- Configuration caching support --------------------------------
368
369 ConfigurationImpl getCachedConfiguration( String pid )
370 {
371 synchronized ( configurations )
372 {
373 return ( ConfigurationImpl ) configurations.get( pid );
374 }
375 }
376
377
Felix Meschberger6a698df2009-08-16 18:38:46 +0000378 ConfigurationImpl[] getCachedConfigurations()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000379 {
380 synchronized ( configurations )
381 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000382 return ( ConfigurationImpl[] ) configurations.values().toArray(
383 new ConfigurationImpl[configurations.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000384 }
385 }
386
387
Felix Meschberger2941ef92007-08-20 13:15:16 +0000388 ConfigurationImpl cacheConfiguration( ConfigurationImpl configuration )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000389 {
390 synchronized ( configurations )
391 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000392 Object existing = configurations.get( configuration.getPid() );
393 if ( existing != null )
394 {
395 return ( ConfigurationImpl ) existing;
396 }
397
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000398 configurations.put( configuration.getPid(), configuration );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000399 return configuration;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000400 }
401 }
402
403
404 void removeConfiguration( ConfigurationImpl configuration )
405 {
406 synchronized ( configurations )
407 {
408 configurations.remove( configuration.getPid() );
409 }
410 }
411
412
Felix Meschberger6a698df2009-08-16 18:38:46 +0000413 Factory getCachedFactory( String factoryPid )
414 {
415 synchronized ( factories )
416 {
417 return ( Factory ) factories.get( factoryPid );
418 }
419 }
420
421
422 Factory[] getCachedFactories()
423 {
424 synchronized ( factories )
425 {
426 return ( Factory[] ) factories.values().toArray( new Factory[factories.size()] );
427 }
428 }
429
430
431 void cacheFactory( Factory factory )
432 {
433 synchronized ( factories )
434 {
435 factories.put( factory.getFactoryPid(), factory );
436 }
437 }
438
439
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000440 // ---------- ConfigurationAdminImpl support
Felix Meschberger6a698df2009-08-16 18:38:46 +0000441
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000442 void setDynamicBundleLocation( final String pid, final String location )
443 {
444 if ( dynamicBindings != null )
445 {
446 try
447 {
448 dynamicBindings.putLocation( pid, location );
449 }
450 catch ( IOException ioe )
451 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000452 log( LogService.LOG_ERROR, "Failed storing dynamic configuration binding for {0} to {1}", new Object[]
453 { pid, location, ioe } );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000454 }
455 }
456 }
457
458
459 String getDynamicBundleLocation( final String pid )
460 {
461 if ( dynamicBindings != null )
462 {
463 return dynamicBindings.getLocation( pid );
464 }
465
466 return null;
467 }
468
469
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000470 ConfigurationImpl createFactoryConfiguration( String factoryPid, String location ) throws IOException
471 {
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000472 return cacheConfiguration( createConfiguration( createPid( factoryPid ), factoryPid, location ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000473 }
474
475
Felix Meschbergerad949872011-11-16 10:34:54 +0000476 /**
477 * Returns the {@link ConfigurationImpl} with the given PID if
478 * available in the internal cache or from any persistence manager.
479 * Otherwise <code>null</code> is returned.
480 *
481 * @param pid The PID for which to return the configuration
482 * @return The configuration or <code>null</code> if non exists
483 * @throws IOException If an error occurrs reading from a persistence
484 * manager.
485 */
486 ConfigurationImpl getConfiguration( String pid ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000487 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000488 ConfigurationImpl config = getCachedConfiguration( pid );
489 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000490 {
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000491 log( LogService.LOG_DEBUG, "Found cached configuration {0} bound to {1}", new Object[]
492 { pid, config.getBundleLocation() } );
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000493
494 config.ensureFactoryConfigPersisted();
495
Felix Meschberger2941ef92007-08-20 13:15:16 +0000496 return config;
497 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000498
Felix Meschberger2941ef92007-08-20 13:15:16 +0000499 PersistenceManager[] pmList = getPersistenceManagers();
500 for ( int i = 0; i < pmList.length; i++ )
501 {
502 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000503 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000504 Dictionary props = pmList[i].load( pid );
505 config = new ConfigurationImpl( this, pmList[i], props );
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000506 log( LogService.LOG_DEBUG, "Found existing configuration {0} bound to {1}", new Object[]
507 { pid, config.getBundleLocation() } );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000508 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000509 }
510 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000511
Felix Meschberger2941ef92007-08-20 13:15:16 +0000512 // neither the cache nor any persistence manager has configuration
513 return null;
514 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000515
516
Felix Meschbergerad949872011-11-16 10:34:54 +0000517 /**
518 * Creates a regular (non-factory) configuration for the given PID
519 * setting the bundle location accordingly.
520 * <p>
521 * This method assumes the configuration to not exist yet and will
522 * create it without further checking.
523 *
524 * @param pid The PID of the new configuration
525 * @param bundleLocation The location to set on the new configuration.
526 * This may be <code>null</code> to not bind the configuration
527 * yet.
528 * @return The new configuration persisted in the first persistence
529 * manager.
530 * @throws IOException If an error occurrs writing the configuration
531 * to the persistence.
532 */
533 ConfigurationImpl createConfiguration( String pid, String bundleLocation ) throws IOException
Felix Meschberger2941ef92007-08-20 13:15:16 +0000534 {
535 // check for existing (cached or persistent) configuration
Felix Meschbergerad949872011-11-16 10:34:54 +0000536 ConfigurationImpl config = getConfiguration( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000537 if ( config != null )
538 {
539 return config;
540 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000541
Felix Meschberger2941ef92007-08-20 13:15:16 +0000542 // else create new configuration also setting the bundle location
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000543 // and cache the new configuration
544 config = createConfiguration( pid, null, bundleLocation );
545 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000546 }
547
548
549 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
550 throws IOException, InvalidSyntaxException
551 {
552 Filter filter = null;
553 if ( filterString != null )
554 {
555 filter = bundleContext.createFilter( filterString );
556 }
557
Felix Meschberger4f269292011-10-21 13:52:31 +0000558 log( LogService.LOG_DEBUG, "Listing configurations matching {0}", new Object[]
559 { filterString } );
560
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000561 List configList = new ArrayList();
562
563 PersistenceManager[] pmList = getPersistenceManagers();
564 for ( int i = 0; i < pmList.length; i++ )
565 {
566 Enumeration configs = pmList[i].getDictionaries();
567 while ( configs.hasMoreElements() )
568 {
569 Dictionary config = ( Dictionary ) configs.nextElement();
570
571 // ignore non-Configuration dictionaries
Felix Meschberger86a0d172007-07-04 07:15:01 +0000572 String pid = ( String ) config.get( Constants.SERVICE_PID );
573 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000574 {
575 continue;
576 }
577
Felix Meschberger007c50e2011-10-20 12:39:38 +0000578 // CM 1.4 / 104.13.2.3 Permission required
579 if ( !configurationAdmin.hasPermission( ( String ) config
580 .get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000581 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000582 log(
583 LogService.LOG_DEBUG,
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000584 "Omitting configuration {0}: No permission for bundle {1} on configuration bound to {2}",
Felix Meschberger4f269292011-10-21 13:52:31 +0000585 new Object[]
586 { config.get( Constants.SERVICE_PID ), configurationAdmin.getBundle().getLocation(),
587 config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000588 continue;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000589 }
590
591 // check filter
592 if ( filter == null || filter.match( config ) )
593 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000594 // ensure the service.pid and returned a cached config if available
595 ConfigurationImpl cfg = getCachedConfiguration( pid );
596 if ( cfg == null )
597 {
598 cfg = new ConfigurationImpl( this, pmList[i], config );
599 }
600
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000601 // FELIX-611: Ignore configuration objects without props
602 if ( !cfg.isNew() )
603 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000604 log( LogService.LOG_DEBUG, "Adding configuration {0}", new Object[]
605 { config.get( Constants.SERVICE_PID ) } );
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000606 configList.add( cfg );
607 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000608 else
609 {
610 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Is new", new Object[]
611 { config.get( Constants.SERVICE_PID ) } );
612 }
613 } else {
614 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Does not match filter", new Object[]
615 { config.get( Constants.SERVICE_PID ) } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000616 }
617 }
618 }
619
Felix Meschberger8faceff2007-07-04 07:19:48 +0000620 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000621 .size()] );
622 }
623
624
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000625 void deleted( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000626 {
627 // remove the configuration from the cache
628 removeConfiguration( config );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000629 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, config.getPid(), config.getFactoryPid() );
630 updateThread.schedule( new DeleteConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000631 log( LogService.LOG_DEBUG, "DeleteConfiguration({0}) scheduled", new Object[]
632 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000633 }
634
635
Felix Meschbergerce67d732009-08-20 06:26:35 +0000636 void updated( ConfigurationImpl config, boolean fireEvent )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000637 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000638 if ( fireEvent )
639 {
640 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPid(), config.getFactoryPid() );
641 }
642 updateThread.schedule( new UpdateConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000643 log( LogService.LOG_DEBUG, "UpdateConfiguration({0}) scheduled", new Object[]
644 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000645 }
646
647
Felix Meschberger007c50e2011-10-20 12:39:38 +0000648 void locationChanged( ConfigurationImpl config, String oldLocation )
649 {
650 fireConfigurationEvent( ConfigurationEvent.CM_LOCATION_CHANGED, config.getPid(), config.getFactoryPid() );
Felix Meschberger35658d52011-10-20 21:43:58 +0000651 if ( oldLocation != null && !config.isNew() )
Felix Meschberger007c50e2011-10-20 12:39:38 +0000652 {
653 updateThread.schedule( new LocationChanged( config, oldLocation ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000654 log( LogService.LOG_DEBUG, "LocationChanged({0}, {1}=>{2}) scheduled", new Object[]
655 { config.getPid(), oldLocation, config.getBundleLocation() } );
Felix Meschberger35658d52011-10-20 21:43:58 +0000656 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000657 else
Felix Meschberger35658d52011-10-20 21:43:58 +0000658 {
659 log( LogService.LOG_DEBUG,
Felix Meschberger4f269292011-10-21 13:52:31 +0000660 "LocationChanged not scheduled for {0} (old location is null or configuration is new)", new Object[]
661 { config.getPid() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000662 }
663 }
664
665
Felix Meschberger66423332007-08-22 08:46:34 +0000666 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000667 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000668 FireConfigurationEvent event = new FireConfigurationEvent( type, pid, factoryPid );
Felix Meschberger0770cad2012-06-11 12:36:52 +0000669 event.fireSynchronousEvents();
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000670 if ( event.hasConfigurationEventListeners() )
671 {
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000672 eventThread.schedule( event );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000673 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000674 else
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000675 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000676 log( LogService.LOG_DEBUG, "No ConfigurationListeners to send {0} event to.", new Object[]
677 { event.getTypeName() } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000678 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000679 }
680
681
682 // ---------- BundleListener -----------------------------------------------
683
684 public void bundleChanged( BundleEvent event )
685 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000686 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000687 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000688 final String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000689
Felix Meschberger6a698df2009-08-16 18:38:46 +0000690 // we only reset dynamic bindings, which are only present in
691 // cached configurations, hence only consider cached configs here
692 final ConfigurationImpl[] configs = getCachedConfigurations();
693 for ( int i = 0; i < configs.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000694 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000695 final ConfigurationImpl cfg = configs[i];
Felix Meschberger41cce522009-08-19 05:54:40 +0000696 if ( location.equals( cfg.getDynamicBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000697 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000698 cfg.setDynamicBundleLocation( null, true );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000699 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000700 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000701 }
702 }
703
704
705 // ---------- internal -----------------------------------------------------
706
707 private PersistenceManager[] getPersistenceManagers()
708 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000709 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
710 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000711 {
712
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000713 List pmList = new ArrayList();
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000714 PersistenceManager[] pm;
715
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000716 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
717 if ( refs == null || refs.length == 0 )
718 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000719 pm = new PersistenceManager[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000720 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000721 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000722 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000723 // sort the references according to the cmRanking property
Felix Meschberger007c50e2011-10-20 12:39:38 +0000724 if ( refs.length > 1 )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000725 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000726 Arrays.sort( refs, RankingComparator.SRV_RANKING );
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000727 }
728
729 // create the service array from the sorted set of referenecs
Felix Meschberger007c50e2011-10-20 12:39:38 +0000730 for ( int i = 0; i < refs.length; i++ )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000731 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000732 Object service = persistenceManagerTracker.getService( refs[i] );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000733 if ( service != null )
734 {
Felix Meschbergera86cdfc2010-08-25 09:32:36 +0000735 pmList.add( new CachingPersistenceManagerProxy( ( PersistenceManager ) service ) );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000736 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000737 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000738
739 pm = ( PersistenceManager[] ) pmList.toArray( new PersistenceManager[pmList.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000740 }
741
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000742 pmtCount = pm.length;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000743 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000744 }
745
746 return persistenceManagers;
747 }
748
749
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000750 private ServiceReference getServiceReference()
751 {
752 ServiceRegistration reg = configurationAdminRegistration;
Felix Meschberger0770cad2012-06-11 12:36:52 +0000753 if (reg != null) {
754 return reg.getReference();
755 }
756
757 // probably called for firing an event during service registration
758 // since we didn't get the service registration yet we use the
759 // service registry to get our service reference
760 BundleContext context = bundleContext;
761 if ( context != null )
762 {
763 try
764 {
765 ServiceReference[] refs = context.getServiceReferences( ConfigurationAdmin.class.getName(), null );
766 if ( refs != null )
767 {
768 for ( int i = 0; i < refs.length; i++ )
769 {
770 if ( refs[i].getBundle().getBundleId() == context.getBundle().getBundleId() )
771 {
772 return refs[i];
773 }
774 }
775 }
776 }
777 catch ( InvalidSyntaxException e )
778 {
779 // unexpected since there is no filter
780 }
781 }
782
783 // service references
784 return null;
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000785 }
786
787
Felix Meschberger05d89e12011-11-03 23:37:10 +0000788 /**
789 * Configures the ManagedService and returns the service.pid
790 * service property as a String[], which may be <code>null</code> if
791 * the ManagedService does not have such a property.
792 */
Felix Meschberger05d89e12011-11-03 23:37:10 +0000793 /**
794 * Configures the ManagedServiceFactory and returns the service.pid
795 * service property as a String[], which may be <code>null</code> if
796 * the ManagedServiceFactory does not have such a property.
797 */
Felix Meschberger382a19b2012-07-03 09:45:14 +0000798 /**
799 * Schedules the configuration of the referenced service with
800 * configuration for the given PID.
801 *
802 * @param pid The service PID of the configuration to be provided
803 * to the referenced service.
804 * @param sr The <code>ServiceReference</code> to the service
805 * to be configured.
806 * @param factory <code>true</code> If the service is considered to
807 * be a <code>ManagedServiceFactory</code>. Otherwise the service
808 * is considered to be a <code>ManagedService</code>.
809 */
810 public void configure( String pid, ServiceReference sr, final boolean factory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000811 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000812 Runnable r;
813 if ( factory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000814 {
Felix Meschberger382a19b2012-07-03 09:45:14 +0000815 r = new ManagedServiceFactoryUpdate( pid, sr );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000816 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000817 else
818 {
Felix Meschberger382a19b2012-07-03 09:45:14 +0000819 r = new ManagedServiceUpdate( pid, sr );
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000820 }
821 updateThread.schedule( r );
822 log( LogService.LOG_DEBUG, "[{0}] scheduled", new Object[]
823 { r } );
Felix Meschberger851c6412009-08-16 18:43:26 +0000824 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000825
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000826
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000827 /**
828 * Factory method to create a new configuration object. The configuration
829 * object returned is not stored in configuration cache and only persisted
830 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000831 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000832 * @param pid
833 * The PID of the new configuration object. Must not be
834 * <code>null</code>.
835 * @param factoryPid
836 * The factory PID of the new configuration. Not
Felix Meschberger6a698df2009-08-16 18:38:46 +0000837 * <code>null</code> if the new configuration object belongs to a
838 * factory. The configuration object will not be persisted if
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000839 * this parameter is not <code>null</code>.
840 * @param bundleLocation
841 * The bundle location of the bundle to which the configuration
Felix Meschberger6a698df2009-08-16 18:38:46 +0000842 * belongs or <code>null</code> if the configuration is not bound
843 * yet.
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000844 * @return The new configuration object
845 * @throws IOException
846 * May be thrown if an error occurrs persisting the new
847 * configuration object.
848 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000849 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000850 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000851 log( LogService.LOG_DEBUG, "createConfiguration({0}, {1}, {2})", new Object[]
852 { pid, factoryPid, bundleLocation } );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000853 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000854 }
855
856
857 Factory getFactory( String factoryPid ) throws IOException
858 {
Felix Meschbergerf4631322008-03-10 12:32:35 +0000859 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000860 if ( factory != null )
861 {
862 return factory;
863 }
864
865 PersistenceManager[] pmList = getPersistenceManagers();
866 for ( int i = 0; i < pmList.length; i++ )
867 {
868 if ( Factory.exists( pmList[i], factoryPid ) )
869 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000870 factory = Factory.load( this, pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000871 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000872 return factory;
873 }
874 }
875
876 // if getting here, there is no configuration yet, optionally create new
877 return createFactory( factoryPid );
878 }
879
880
881 Factory createFactory( String factoryPid )
882 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000883 Factory factory = new Factory( this, getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000884 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000885 return factory;
886 }
887
888
Felix Meschberger2941ef92007-08-20 13:15:16 +0000889 /**
890 * Calls the registered configuration plugins on the given configuration
Felix Meschberger41cce522009-08-19 05:54:40 +0000891 * properties from the given configuration object unless the configuration
892 * has just been created and not been updated yet.
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000893 *
Felix Meschberger41cce522009-08-19 05:54:40 +0000894 * @param props The configuraiton properties run through the registered
895 * ConfigurationPlugin services. This may be <code>null</code>
896 * in which case this method just immediately returns.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000897 * @param targetPid The identification of the configuration update used to
898 * select the plugins according to their cm.target service
899 * property
Felix Meschberger2941ef92007-08-20 13:15:16 +0000900 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000901 * is to be updated with configuration
Felix Meschberger2941ef92007-08-20 13:15:16 +0000902 * @param cfg The configuration object whose properties have to be passed
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000903 * through the plugins
Felix Meschberger2941ef92007-08-20 13:15:16 +0000904 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000905 public void callPlugins( final Dictionary props, final String targetPid, final ServiceReference sr,
Felix Meschberger41cce522009-08-19 05:54:40 +0000906 final ConfigurationImpl cfg )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000907 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000908 // guard against NPE for new configuration never updated
909 if (props == null) {
Felix Meschberger41cce522009-08-19 05:54:40 +0000910 return;
Felix Meschberger2941ef92007-08-20 13:15:16 +0000911 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000912
913 ServiceReference[] plugins = null;
914 try
915 {
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000916 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000917 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000918 }
919 catch ( InvalidSyntaxException ise )
920 {
921 // no filter, no exception ...
922 }
923
924 // abort early if there are no plugins
925 if ( plugins == null || plugins.length == 0 )
926 {
Felix Meschberger41cce522009-08-19 05:54:40 +0000927 return;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000928 }
929
930 // sort the plugins by their service.cmRanking
Felix Meschberger007c50e2011-10-20 12:39:38 +0000931 if ( plugins.length > 1 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000932 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000933 Arrays.sort( plugins, RankingComparator.CM_RANKING );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000934 }
935
936 // call the plugins in order
Felix Meschberger007c50e2011-10-20 12:39:38 +0000937 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000938 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000939 ServiceReference pluginRef = plugins[i];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000940 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000941 if ( plugin != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000942 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000943 try
944 {
945 plugin.modifyConfiguration( sr, props );
946 }
947 catch ( Throwable t )
948 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000949 log( LogService.LOG_ERROR, "Unexpected problem calling configuration plugin {0}", new Object[]
950 { toString( pluginRef ), t } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000951 }
952 finally
953 {
954 // ensure ungetting the plugin
955 bundleContext.ungetService( pluginRef );
956 }
957 cfg.setAutoProperties( props, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000958 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000959 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000960 }
961
962
963 /**
964 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000965 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000966 * @param factoryPid
967 * @return
968 */
969 private static String createPid( String factoryPid )
970 {
Felix Meschberger417f66c2011-02-04 11:25:23 +0000971 Random ng = numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000972 if ( ng == null )
973 {
Felix Meschberger417f66c2011-02-04 11:25:23 +0000974 // FELIX-2771 Secure Random not available on Mika
975 try
976 {
977 ng = new SecureRandom();
978 }
979 catch ( Throwable t )
980 {
981 // fall back to Random
982 ng = new Random();
983 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000984 }
985
986 byte[] randomBytes = new byte[16];
987 ng.nextBytes( randomBytes );
988 randomBytes[6] &= 0x0f; /* clear version */
989 randomBytes[6] |= 0x40; /* set to version 4 */
990 randomBytes[8] &= 0x3f; /* clear variant */
991 randomBytes[8] |= 0x80; /* set to IETF variant */
992
993 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
994
995 // prefix the new pid with the factory pid
996 buf.append( factoryPid ).append( "." );
997
998 // serialize the UUID into the buffer
999 for ( int i = 0; i < randomBytes.length; i++ )
1000 {
1001
1002 if ( i == 4 || i == 6 || i == 8 || i == 10 )
1003 {
1004 buf.append( '-' );
1005 }
1006
1007 int val = randomBytes[i] & 0xff;
1008 buf.append( Integer.toHexString( val >> 4 ) );
1009 buf.append( Integer.toHexString( val & 0xf ) );
1010 }
1011
1012 return buf.toString();
1013 }
1014
1015
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001016 public boolean isLogEnabled( int level )
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001017 {
1018 return level <= logLevel;
1019 }
1020
1021
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001022 public void log( int level, String format, Object[] args )
Felix Meschberger4f269292011-10-21 13:52:31 +00001023 {
1024 if ( isLogEnabled( level ) )
1025 {
1026 Throwable throwable = null;
1027 String message = format;
1028
1029 if ( args != null && args.length > 0 )
1030 {
1031 if ( args[args.length - 1] instanceof Throwable )
1032 {
1033 throwable = ( Throwable ) args[args.length - 1];
1034 }
1035 message = MessageFormat.format( format, args );
1036 }
1037
1038 log( level, message, throwable );
1039 }
1040 }
1041
1042
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001043 public void log( int level, String message, Throwable t )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001044 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001045 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +00001046 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001047 if ( log != null )
1048 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +00001049 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001050 return;
1051 }
1052
Felix Meschberger08282c32009-01-28 07:01:55 +00001053 // Otherwise only log if more serious than the configured level
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001054 if ( isLogEnabled( level ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001055 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001056 String code;
1057 switch ( level )
1058 {
1059 case LogService.LOG_INFO:
1060 code = "*INFO *";
1061 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001062
Felix Meschberger08282c32009-01-28 07:01:55 +00001063 case LogService.LOG_WARNING:
1064 code = "*WARN *";
1065 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001066
Felix Meschberger08282c32009-01-28 07:01:55 +00001067 case LogService.LOG_ERROR:
1068 code = "*ERROR*";
1069 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001070
Felix Meschberger08282c32009-01-28 07:01:55 +00001071 case LogService.LOG_DEBUG:
1072 default:
1073 code = "*DEBUG*";
1074 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001075
Felix Meschberger08282c32009-01-28 07:01:55 +00001076 System.err.println( code + " " + message );
1077 if ( t != null )
1078 {
1079 t.printStackTrace( System.err );
1080 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001081 }
1082 }
1083
Felix Meschberger851c6412009-08-16 18:43:26 +00001084
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001085 public static String toString( ServiceReference ref )
Felix Meschberger41cce522009-08-19 05:54:40 +00001086 {
1087 String[] ocs = ( String[] ) ref.getProperty( "objectClass" );
Felix Meschberger382a19b2012-07-03 09:45:14 +00001088 StringBuffer buf = new StringBuffer( "[" );
Felix Meschberger41cce522009-08-19 05:54:40 +00001089 for ( int i = 0; i < ocs.length; i++ )
1090 {
Felix Meschberger382a19b2012-07-03 09:45:14 +00001091 buf.append( ocs[i] );
Felix Meschberger41cce522009-08-19 05:54:40 +00001092 if ( i < ocs.length - 1 )
Felix Meschberger382a19b2012-07-03 09:45:14 +00001093 buf.append( ", " );
Felix Meschberger41cce522009-08-19 05:54:40 +00001094 }
1095
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001096 buf.append( ", id=" ).append( ref.getProperty( Constants.SERVICE_ID ) );
1097
1098 Bundle provider = ref.getBundle();
1099 if ( provider != null )
1100 {
1101 buf.append( ", bundle=" ).append( provider.getBundleId() );
Felix Meschberger0135b322011-11-16 12:30:22 +00001102 buf.append( '/' ).append( provider.getLocation() );
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001103 }
1104 else
1105 {
1106 buf.append( ", unregistered" );
1107 }
1108
1109 buf.append( "]" );
1110 return buf.toString();
Felix Meschberger41cce522009-08-19 05:54:40 +00001111 }
1112
Felix Meschbergerce67d732009-08-20 06:26:35 +00001113
Felix Meschberger007c50e2011-10-20 12:39:38 +00001114 /**
1115 * Checks whether the bundle is allowed to receive the configuration
1116 * with the given location binding.
1117 * <p>
1118 * This method implements the logic defined CM 1.4 / 104.4.1:
1119 * <ul>
1120 * <li>If the location is <code>null</code> (the configuration is not
1121 * bound yet), assume the bundle is allowed</li>
1122 * <li>If the location is a single location (no leading "?"), require
1123 * the bundle's location to match</li>
1124 * <li>If the location is a multi-location (leading "?"), assume the
1125 * bundle is allowed if there is no security manager. If there is a
1126 * security manager, check whether the bundle has "target" permission
1127 * on this location.</li>
1128 * </ul>
1129 */
1130 boolean canReceive( final Bundle bundle, final String location )
1131 {
1132 if ( location == null )
1133 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001134 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration=(unbound)", new Object[]
Felix Meschberger61207232011-11-17 10:06:45 +00001135 { bundle.getLocation() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001136 return true;
1137 }
1138 else if ( location.startsWith( "?" ) )
1139 {
1140 // multi-location
1141 if ( System.getSecurityManager() != null )
1142 {
Felix Meschberger61207232011-11-17 10:06:45 +00001143 final boolean hasPermission = bundle.hasPermission( new ConfigurationPermission( location,
1144 ConfigurationPermission.TARGET ) );
1145 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2} (SecurityManager check)",
1146 new Object[]
1147 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1148 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001149 }
Felix Meschberger61207232011-11-17 10:06:45 +00001150
1151 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration={1} (no SecurityManager)",
1152 new Object[]
1153 { bundle.getLocation(), location } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001154 return true;
1155 }
1156 else
1157 {
1158 // single location, must match
Felix Meschberger61207232011-11-17 10:06:45 +00001159 final boolean hasPermission = location.equals( bundle.getLocation() );
1160 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2}", new Object[]
1161 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1162 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001163 }
1164 }
1165
Felix Meschberger61207232011-11-17 10:06:45 +00001166
Felix Meschberger007c50e2011-10-20 12:39:38 +00001167 // ---------- inner classes
1168
Felix Meschberger007c50e2011-10-20 12:39:38 +00001169 /**
1170 * The <code>ManagedServiceUpdate</code> updates a freshly registered
1171 * <code>ManagedService</code> with a specific configuration. If a
1172 * ManagedService is registered with multiple PIDs an instance of this
1173 * class is used for each registered PID.
1174 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001175 private class ManagedServiceUpdate implements Runnable
1176 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001177 private final String pid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001178
Felix Meschberger41cce522009-08-19 05:54:40 +00001179 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001180
Felix Meschberger41cce522009-08-19 05:54:40 +00001181 private final ConfigurationImpl config;
1182
1183 private final Dictionary rawProperties;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001184
Felix Meschberger61207232011-11-17 10:06:45 +00001185 private final long revision;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001186
Felix Meschberger382a19b2012-07-03 09:45:14 +00001187 ManagedServiceUpdate( String pid, ServiceReference sr )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001188 {
1189 this.pid = pid;
1190 this.sr = sr;
Felix Meschberger41cce522009-08-19 05:54:40 +00001191
1192 // get or load configuration for the pid
1193 ConfigurationImpl config = null;
1194 Dictionary rawProperties = null;
Felix Meschberger61207232011-11-17 10:06:45 +00001195 long revision = -1;
Felix Meschberger41cce522009-08-19 05:54:40 +00001196 try
1197 {
Felix Meschbergerad949872011-11-16 10:34:54 +00001198 config = getConfiguration( pid );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001199 if ( config != null )
1200 {
1201 synchronized ( config )
1202 {
1203 rawProperties = config.getProperties( true );
Felix Meschberger61207232011-11-17 10:06:45 +00001204 revision = config.getRevision();
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001205 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001206 }
1207 }
1208 catch ( IOException ioe )
1209 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001210 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1211 { pid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001212 }
1213
1214 this.config = config;
1215 this.rawProperties = rawProperties;
Felix Meschberger61207232011-11-17 10:06:45 +00001216 this.revision = revision;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001217 }
1218
1219
1220 public void run()
1221 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001222 Dictionary properties = rawProperties;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001223
1224 // check configuration and call plugins if existing
Felix Meschberger41cce522009-08-19 05:54:40 +00001225 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001226 {
Felix Meschberger61207232011-11-17 10:06:45 +00001227 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1228 { pid, new Long( revision ) } );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001229
Felix Meschberger41243192009-01-14 19:59:58 +00001230 Bundle serviceBundle = sr.getBundle();
1231 if ( serviceBundle == null )
1232 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001233 log( LogService.LOG_INFO,
1234 "Service for PID {0} seems to already have been unregistered, not updating with configuration",
1235 new Object[]
1236 { pid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001237 return;
1238 }
1239
Felix Meschberger27689c12011-11-16 08:52:04 +00001240 if ( canReceive( serviceBundle, config.getBundleLocation() ) )
Felix Meschberger2941ef92007-08-20 13:15:16 +00001241 {
Felix Meschberger27689c12011-11-16 08:52:04 +00001242 // 104.4.2 Dynamic Binding
1243 config.tryBindLocation( serviceBundle.getLocation() );
Felix Meschberger27689c12011-11-16 08:52:04 +00001244 }
1245 else
1246 {
1247 // CM 1.4 / 104.13.2.2 / 104.5.3
1248 // act as if there is no configuration
1249 log(
1250 LogService.LOG_DEBUG,
1251 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}; calling with null",
Felix Meschberger4f269292011-10-21 13:52:31 +00001252 new Object[]
1253 { pid, ConfigurationManager.toString( sr ), config.getBundleLocation() } );
Felix Meschberger27689c12011-11-16 08:52:04 +00001254
1255 // CM 1.4 / 104.5.3 ManagedService.updated must be
1256 // called with null if configuration is no visible
1257 properties = null;
Felix Meschberger2941ef92007-08-20 13:15:16 +00001258 }
1259
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001260 }
1261 else
1262 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001263 // 104.5.3 ManagedService.updated must be called with null
1264 // if no configuration is available
Felix Meschberger41cce522009-08-19 05:54:40 +00001265 properties = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001266 }
1267
Felix Meschberger382a19b2012-07-03 09:45:14 +00001268 managedServiceTracker.provideConfiguration( sr, config, properties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001269 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001270
Felix Meschberger432e3872008-03-07 14:58:57 +00001271 public String toString()
1272 {
1273 return "ManagedService Update: pid=" + pid;
1274 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001275 }
1276
Felix Meschberger007c50e2011-10-20 12:39:38 +00001277 /**
1278 * The <code>ManagedServiceFactoryUpdate</code> updates a freshly
1279 * registered <code>ManagedServiceFactory</code> with a specific
1280 * configuration. If a ManagedServiceFactory is registered with
1281 * multiple PIDs an instance of this class is used for each registered
1282 * PID.
1283 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001284 private class ManagedServiceFactoryUpdate implements Runnable
1285 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001286 private final String factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001287
Felix Meschberger41cce522009-08-19 05:54:40 +00001288 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001289
Felix Meschberger41cce522009-08-19 05:54:40 +00001290 private final Map configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001291
Felix Meschberger61207232011-11-17 10:06:45 +00001292 private final Map revisions;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001293
Felix Meschberger382a19b2012-07-03 09:45:14 +00001294 ManagedServiceFactoryUpdate( String factoryPid, ServiceReference sr )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001295 {
1296 this.factoryPid = factoryPid;
1297 this.sr = sr;
Felix Meschberger41cce522009-08-19 05:54:40 +00001298
1299 Factory factory = null;
1300 Map configs = null;
Felix Meschberger61207232011-11-17 10:06:45 +00001301 Map revisions = null;
Felix Meschberger41cce522009-08-19 05:54:40 +00001302 try
1303 {
1304 factory = getFactory( factoryPid );
1305 if (factory != null) {
1306 configs = new HashMap();
Felix Meschberger61207232011-11-17 10:06:45 +00001307 revisions = new HashMap();
Felix Meschberger41cce522009-08-19 05:54:40 +00001308 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
1309 {
1310 final String pid = ( String ) pi.next();
1311 ConfigurationImpl cfg;
1312 try
1313 {
Felix Meschbergerad949872011-11-16 10:34:54 +00001314 cfg = getConfiguration( pid );
Felix Meschberger41cce522009-08-19 05:54:40 +00001315 }
1316 catch ( IOException ioe )
1317 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001318 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1319 { pid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001320 continue;
1321 }
1322
1323 // sanity check on the configuration
1324 if ( cfg == null )
1325 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001326 log( LogService.LOG_ERROR, "Configuration {0} referred to by factory {1} does not exist",
1327 new Object[]
1328 { pid, factoryPid } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001329 factory.removePID( pid );
1330 factory.storeSilently();
1331 continue;
1332 }
1333 else if ( cfg.isNew() )
1334 {
1335 // Configuration has just been created but not yet updated
1336 // we currently just ignore it and have the update mechanism
1337 // provide the configuration to the ManagedServiceFactory
1338 // As of FELIX-612 (not storing new factory configurations)
1339 // this should not happen. We keep this for added stability
1340 // but raise the logging level to error.
Felix Meschberger4f269292011-10-21 13:52:31 +00001341 log( LogService.LOG_ERROR, "Ignoring new configuration pid={0}", new Object[]
1342 { pid } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001343 continue;
1344 }
1345 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1346 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001347 log( LogService.LOG_ERROR,
1348 "Configuration {0} referred to by factory {1} seems to belong to factory {2}",
1349 new Object[]
1350 { pid, factoryPid, cfg.getFactoryPid() } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001351 factory.removePID( pid );
1352 factory.storeSilently();
1353 continue;
1354 }
1355
1356 // get the configuration properties for later
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001357 synchronized ( cfg )
1358 {
1359 configs.put( cfg, cfg.getProperties( true ) );
Felix Meschberger61207232011-11-17 10:06:45 +00001360 revisions.put( cfg, new Long( cfg.getRevision() ) );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001361 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001362 }
1363 }
1364 }
1365 catch ( IOException ioe )
1366 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001367 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID {0}", new Object[]
1368 { factoryPid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001369 }
1370
Felix Meschberger41cce522009-08-19 05:54:40 +00001371 this.configs = configs;
Felix Meschberger61207232011-11-17 10:06:45 +00001372 this.revisions = revisions;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001373 }
1374
1375
1376 public void run()
1377 {
Felix Meschberger41243192009-01-14 19:59:58 +00001378 Bundle serviceBundle = sr.getBundle();
1379 if ( serviceBundle == null )
1380 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001381 log(
1382 LogService.LOG_INFO,
1383 "ManagedServiceFactory for factory PID {0} seems to already have been unregistered, not updating with factory",
1384 new Object[]
1385 { factoryPid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001386 return;
1387 }
1388
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001389 if ( configs == null || configs.isEmpty() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001390 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001391 log( LogService.LOG_DEBUG, "No configuration with factory PID {0}; not updating ManagedServiceFactory",
1392 new Object[]
1393 { factoryPid } );
1394 }
1395 else
1396 {
1397 for ( Iterator ci = configs.entrySet().iterator(); ci.hasNext(); )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001398 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001399 final Map.Entry entry = ( Map.Entry ) ci.next();
1400 final ConfigurationImpl cfg = ( ConfigurationImpl ) entry.getKey();
1401 final Dictionary properties = ( Dictionary ) entry.getValue();
1402 final long revision = ( ( Long ) revisions.get( cfg ) ).longValue();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001403
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001404 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1405 { cfg.getPid(), new Long( revision ) } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001406
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001407 // CM 1.4 / 104.13.2.1
1408 if ( !canReceive( serviceBundle, cfg.getBundleLocation() ) )
Felix Meschberger2941ef92007-08-20 13:15:16 +00001409 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001410 log( LogService.LOG_ERROR,
1411 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1412 new Object[]
1413 { cfg.getPid(), ConfigurationManager.toString( sr ), cfg.getBundleLocation() } );
1414 continue;
Felix Meschberger2941ef92007-08-20 13:15:16 +00001415 }
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001416
1417 // 104.4.2 Dynamic Binding
1418 cfg.tryBindLocation( serviceBundle.getLocation() );
1419
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001420 // update the service with the configuration (if non-null)
1421 if ( properties != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001422 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001423 log( LogService.LOG_DEBUG, "{0}: Updating configuration pid={1}", new Object[]
1424 { ConfigurationManager.toString( sr ), cfg.getPid() } );
Felix Meschberger382a19b2012-07-03 09:45:14 +00001425 managedServiceFactoryTracker.provideConfiguration( sr, cfg, properties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001426 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001427 }
1428 }
1429 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001430
1431
Felix Meschberger432e3872008-03-07 14:58:57 +00001432 public String toString()
1433 {
1434 return "ManagedServiceFactory Update: factoryPid=" + factoryPid;
1435 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001436 }
1437
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001438 private abstract class ConfigurationProvider<T> implements Runnable {
1439
1440 protected final ConfigurationImpl config;
1441 protected final long revision;
1442 protected final Dictionary<String, ?> properties;
1443 protected final BaseTracker<T> helper;
1444
1445 protected ConfigurationProvider(final ConfigurationImpl config) {
1446 this.config = config;
1447 this.helper = ( BaseTracker<T> ) ( ( config.getFactoryPid() == null ) ? managedServiceTracker : managedServiceFactoryTracker );
1448 synchronized ( config )
1449 {
1450 this.revision = config.getRevision();
1451 this.properties = config.getProperties( true );
1452 }
1453 }
1454
1455 protected TargetedPID getTargetedServicePid() {
1456 final String factoryPid = this.config.getFactoryPid();
1457 if (factoryPid == null) {
1458 return new TargetedPID( this.config.getPid() );
1459 }
1460 return new TargetedPID( factoryPid );
1461 }
1462
1463 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001464
1465 /**
1466 * The <code>UpdateConfiguration</code> is used to update
1467 * <code>ManagedService[Factory]</code> services with the configuration
1468 * they are subscribed to. This may cause the configuration to be
1469 * supplied to multiple services.
1470 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001471 private class UpdateConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001472 {
1473
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001474 UpdateConfiguration( final ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001475 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001476 super( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001477 }
1478
1479
1480 public void run()
1481 {
Felix Meschberger61207232011-11-17 10:06:45 +00001482 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1483 { config.getPid(), new Long( revision ) } );
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001484
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001485 final List<ServiceReference<?>> srList = this.helper.getServices( getTargetedServicePid() );
1486 if ( !srList.isEmpty() )
Felix Meschberger41cce522009-08-19 05:54:40 +00001487 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001488 // optionally bind dynamically to the first service
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001489 config.tryBindLocation( srList.get( 0 ).getBundle().getLocation() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001490
1491 final String configBundleLocation = config.getBundleLocation();
1492
1493 // provide configuration to all services from the
1494 // correct bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001495 for (ServiceReference<?> ref : srList)
Felix Meschberger41cce522009-08-19 05:54:40 +00001496 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001497 final Bundle refBundle = ref.getBundle();
1498 if ( refBundle == null )
Felix Meschberger41cce522009-08-19 05:54:40 +00001499 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001500 log( LogService.LOG_DEBUG,
1501 "Service {0} seems to be unregistered concurrently (not providing configuration)",
1502 new Object[]
1503 { ConfigurationManager.toString( ref ) } );
1504 }
1505 else if ( canReceive( refBundle, configBundleLocation ) )
1506 {
Felix Meschbergeraccd9012012-07-02 15:18:08 +00001507 helper.provideConfiguration( ref, this.config, this.properties );
Felix Meschberger2444da62011-11-17 11:17:50 +00001508 }
1509 else
1510 {
1511 // CM 1.4 / 104.13.2.2
Felix Meschberger4f269292011-10-21 13:52:31 +00001512 log( LogService.LOG_ERROR,
1513 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1514 new Object[]
1515 { config.getPid(), ConfigurationManager.toString( ref ), configBundleLocation } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001516 }
1517
Felix Meschberger41cce522009-08-19 05:54:40 +00001518 }
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001519 }
Felix Meschberger137ee722011-11-16 09:51:59 +00001520 else if ( isLogEnabled( LogService.LOG_DEBUG ) )
1521 {
Felix Meschberger1ee888d2011-11-16 12:42:57 +00001522 log( LogService.LOG_DEBUG, "No ManagedService[Factory] registered for updates to configuration {0}",
Felix Meschberger137ee722011-11-16 09:51:59 +00001523 new Object[]
1524 { config.getPid() } );
1525 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001526 }
1527
1528
Felix Meschberger432e3872008-03-07 14:58:57 +00001529 public String toString()
1530 {
1531 return "Update: pid=" + config.getPid();
1532 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001533 }
1534
Felix Meschberger007c50e2011-10-20 12:39:38 +00001535
1536 /**
1537 * The <code>DeleteConfiguration</code> class is used to inform
1538 * <code>ManagedService[Factory]</code> services of a configuration
1539 * being deleted.
1540 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001541 private class DeleteConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001542 {
Felix Meschberger66423332007-08-22 08:46:34 +00001543
Felix Meschbergerc12db8c2009-08-19 06:43:59 +00001544 private final String configLocation;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001545
1546
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001547 DeleteConfiguration( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001548 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001549 /*
1550 * NOTE: We keep the configuration because it might be cleared just
1551 * after calling this method. The pid and factoryPid fields are
1552 * final and cannot be reset.
1553 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001554 super(config);
Felix Meschberger007c50e2011-10-20 12:39:38 +00001555 this.configLocation = config.getBundleLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001556 }
1557
1558
1559 public void run()
1560 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001561 final String pid = config.getPid();
1562 final String factoryPid = config.getFactoryPid();
1563
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001564 List<ServiceReference<?>> srList = this.helper.getServices( getTargetedServicePid() );
1565 if ( !srList.isEmpty() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001566 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001567 for (ServiceReference<?> sr : srList)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001568 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001569 final Bundle srBundle = sr.getBundle();
1570 if ( srBundle == null )
1571 {
1572 log( LogService.LOG_DEBUG,
1573 "Service {0} seems to be unregistered concurrently (not removing configuration)",
1574 new Object[]
1575 { ConfigurationManager.toString( sr ) } );
1576 }
1577 else if ( canReceive( srBundle, configLocation ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001578 {
Felix Meschbergeraccd9012012-07-02 15:18:08 +00001579 this.helper.removeConfiguration( sr, this.config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001580 }
Felix Meschberger2444da62011-11-17 11:17:50 +00001581 else
1582 {
1583 // CM 1.4 / 104.13.2.2
1584 log( LogService.LOG_ERROR,
1585 "Cannot remove configuration {0} for {1}: No visibility to configuration bound to {2}",
1586 new Object[]
1587 { config.getPid(), ConfigurationManager.toString( sr ), configLocation } );
1588 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001589 }
1590 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001591
1592 if ( factoryPid != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001593 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001594 // remove the pid from the factory
1595 try
1596 {
1597 Factory factory = getFactory( factoryPid );
1598 factory.removePID( pid );
1599 factory.store();
1600 }
1601 catch ( IOException ioe )
1602 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001603 log( LogService.LOG_ERROR, "Failed removing {0} from the factory {1}", new Object[]
1604 { pid, factoryPid, ioe } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001605 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001606 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001607 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001608
Felix Meschberger432e3872008-03-07 14:58:57 +00001609 public String toString()
1610 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001611 return "Delete: pid=" + config.getPid();
Felix Meschberger432e3872008-03-07 14:58:57 +00001612 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001613 }
1614
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001615 private class LocationChanged extends ConfigurationProvider
Felix Meschberger007c50e2011-10-20 12:39:38 +00001616 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001617 private final String oldLocation;
1618
1619
1620 LocationChanged( ConfigurationImpl config, String oldLocation )
1621 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001622 super( config );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001623 this.oldLocation = oldLocation;
1624 }
1625
1626
1627 public void run()
1628 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001629 List<ServiceReference<?>> srList = helper.getServices( getTargetedServicePid() );
1630 if ( !srList.isEmpty() )
Felix Meschberger007c50e2011-10-20 12:39:38 +00001631 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001632 for (final ServiceReference<?> sr : srList)
Felix Meschberger007c50e2011-10-20 12:39:38 +00001633 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001634 final Bundle srBundle = sr.getBundle();
1635 if ( srBundle == null )
1636 {
1637 log( LogService.LOG_DEBUG,
1638 "Service {0} seems to be unregistered concurrently (not processing)", new Object[]
1639 { ConfigurationManager.toString( sr ) } );
1640 continue;
1641 }
1642
1643 final boolean wasVisible = canReceive( srBundle, oldLocation );
1644 final boolean isVisible = canReceive( srBundle, config.getBundleLocation() );
1645
1646 // make sure the config is dynamically bound to the first
1647 // service if the config has been unbound causing this update
1648 if ( isVisible )
1649 {
1650 config.tryBindLocation( srBundle.getLocation() );
1651 }
1652
Felix Meschberger007c50e2011-10-20 12:39:38 +00001653 if ( wasVisible && !isVisible )
1654 {
1655 // call deleted method
Felix Meschbergeraccd9012012-07-02 15:18:08 +00001656 helper.removeConfiguration( sr, this.config );
Felix Meschberger4f269292011-10-21 13:52:31 +00001657 log( LogService.LOG_DEBUG, "Configuration {0} revoked from {1} (no more visibility)",
1658 new Object[]
1659 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001660 }
1661 else if ( !wasVisible && isVisible )
1662 {
1663 // call updated method
Felix Meschbergeraccd9012012-07-02 15:18:08 +00001664 helper.provideConfiguration( sr, this.config, this.properties );
Felix Meschberger4f269292011-10-21 13:52:31 +00001665 log( LogService.LOG_DEBUG, "Configuration {0} provided to {1} (new visibility)", new Object[]
1666 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger35658d52011-10-20 21:43:58 +00001667 }
Felix Meschberger4f269292011-10-21 13:52:31 +00001668 else
Felix Meschberger35658d52011-10-20 21:43:58 +00001669 {
1670 // same visibility as before
Felix Meschberger4f269292011-10-21 13:52:31 +00001671 log( LogService.LOG_DEBUG, "Unmodified visibility to configuration {0} for {1}", new Object[]
1672 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001673 }
1674 }
1675 }
1676 }
1677
1678
1679 public String toString()
1680 {
1681 return "Location Changed (pid=" + config.getPid() + "): " + oldLocation + " ==> "
1682 + config.getBundleLocation();
1683 }
1684 }
1685
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001686 private class FireConfigurationEvent implements Runnable
1687 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001688 private final int type;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001689
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001690 private final String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001691
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001692 private final String factoryPid;
1693
1694 private final ServiceReference[] listenerReferences;
1695
1696 private final ConfigurationListener[] listeners;
1697
1698 private final Bundle[] listenerProvider;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001699
Felix Meschberger0770cad2012-06-11 12:36:52 +00001700 private ConfigurationEvent event;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001701
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001702 private FireConfigurationEvent( final int type, final String pid, final String factoryPid)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001703 {
1704 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001705 this.pid = pid;
1706 this.factoryPid = factoryPid;
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001707
1708 final ServiceReference[] srs = configurationListenerTracker.getServiceReferences();
1709 if ( srs == null || srs.length == 0 )
1710 {
1711 this.listenerReferences = null;
1712 this.listeners = null;
1713 this.listenerProvider = null;
1714 }
1715 else
1716 {
1717 this.listenerReferences = srs;
1718 this.listeners = new ConfigurationListener[srs.length];
1719 this.listenerProvider = new Bundle[srs.length];
1720 for ( int i = 0; i < srs.length; i++ )
1721 {
1722 this.listeners[i] = ( ConfigurationListener ) configurationListenerTracker.getService( srs[i] );
1723 this.listenerProvider[i] = srs[i].getBundle();
1724 }
1725 }
1726 }
1727
1728
Felix Meschberger0770cad2012-06-11 12:36:52 +00001729 void fireSynchronousEvents()
1730 {
1731 if ( hasConfigurationEventListeners() && getServiceReference() != null )
1732 {
1733 for ( int i = 0; i < this.listeners.length; i++ )
1734 {
1735 if ( this.listeners[i] instanceof SynchronousConfigurationListener )
1736 {
1737 sendEvent( i );
1738 }
1739 }
1740 }
1741 }
1742
1743
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001744 boolean hasConfigurationEventListeners()
1745 {
1746 return this.listenerReferences != null;
1747 }
1748
1749
1750 String getTypeName()
1751 {
1752 switch ( type )
1753 {
1754 case ConfigurationEvent.CM_DELETED:
1755 return "CM_DELETED";
1756 case ConfigurationEvent.CM_UPDATED:
1757 return "CM_UPDATED";
Felix Meschberger007c50e2011-10-20 12:39:38 +00001758 case ConfigurationEvent.CM_LOCATION_CHANGED:
1759 return "CM_LOCATION_CHANGED";
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001760 default:
1761 return "<UNKNOWN(" + type + ")>";
1762 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001763 }
1764
1765
1766 public void run()
1767 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001768 for ( int i = 0; i < listeners.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001769 {
Felix Meschberger0770cad2012-06-11 12:36:52 +00001770 sendEvent( i );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001771 }
1772 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001773
Felix Meschberger0770cad2012-06-11 12:36:52 +00001774
Felix Meschberger432e3872008-03-07 14:58:57 +00001775 public String toString()
1776 {
1777 return "Fire ConfigurationEvent: pid=" + pid;
1778 }
Felix Meschberger0770cad2012-06-11 12:36:52 +00001779
1780
1781 private ConfigurationEvent getConfigurationEvent()
1782 {
1783 if ( event == null )
1784 {
1785 this.event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
1786 }
1787 return event;
1788 }
1789
1790
1791 private void sendEvent( final int serviceIndex )
1792 {
1793 if ( listenerProvider[serviceIndex].getState() == Bundle.ACTIVE && this.listeners[serviceIndex] != null )
1794 {
1795 log( LogService.LOG_DEBUG, "Sending {0} event for {1} to {2}", new Object[]
1796 { getTypeName(), pid, ConfigurationManager.toString( listenerReferences[serviceIndex] ) } );
1797
1798 try
1799 {
1800 listeners[serviceIndex].configurationEvent( getConfigurationEvent() );
1801 }
1802 catch ( Throwable t )
1803 {
1804 log( LogService.LOG_ERROR, "Unexpected problem delivering configuration event to {0}", new Object[]
1805 { ConfigurationManager.toString( listenerReferences[serviceIndex] ), t } );
1806 }
1807 finally
1808 {
1809 this.listeners[serviceIndex] = null;
1810 }
1811 }
1812 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001813 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001814}