blob: b0d1ba4da785cae303bb78cb918fb450bc5c91b6 [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;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000034import 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
Felix Meschbergere94b1572012-07-14 11:59:29 +0000138 // the synchronous ConfigurationEvent listeners
139 private ServiceTracker syncConfigurationListenerTracker;
140
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000141 // service tracker for managed services
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000142 private ManagedServiceTracker managedServiceTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000143
144 // service tracker for managed service factories
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000145 private ManagedServiceFactoryTracker managedServiceFactoryTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000146
147 // PersistenceManager services
148 private ServiceTracker persistenceManagerTracker;
149
150 // the thread used to schedule tasks required to run asynchronously
151 private UpdateThread updateThread;
152
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000153 // the thread used to schedule events to be dispatched asynchronously
154 private UpdateThread eventThread;
155
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000156 /**
157 * The actual list of {@link PersistenceManager persistence managers} to use
158 * when looking for configuration data. This list is built from the
159 * {@link #persistenceManagerMap}, which is ordered according to the
160 * {@link RankingComparator}.
161 */
162 private PersistenceManager[] persistenceManagers;
163
164 // the persistenceManagerTracker.getTrackingCount when the
165 // persistenceManagers were last got
166 private int pmtCount;
167
168 // the cache of Factory instances mapped by their factory PID
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000169 private final HashMap<String, Factory> factories = new HashMap<String, Factory>();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000170
171 // the cache of Configuration instances mapped by their PID
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000172 // have this always set to prevent NPE on bundle shutdown
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000173 private final HashMap<String, ConfigurationImpl> configurations = new HashMap<String, ConfigurationImpl>();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000174
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000175 /**
176 * The map of dynamic configuration bindings. This maps the
177 * PID of the dynamically bound configuration or factory to its bundle
178 * location.
179 * <p>
180 * On bundle startup this map is loaded from persistence and validated
181 * against the locations of installed bundles: Entries pointing to bundle
182 * locations not currently installed are removed.
183 * <p>
184 * The map is written to persistence on each change.
185 */
186 private DynamicBindings dynamicBindings;
187
Felix Meschberger08282c32009-01-28 07:01:55 +0000188 // the maximum log level when no LogService is available
189 private int logLevel = CM_LOG_LEVEL_DEFAULT;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000190
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000191 // flag indicating whether BundleChange events should be consumed (FELIX-979)
192 private volatile boolean handleBundleEvents;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000193
Felix Meschberger623f7142012-01-31 07:13:37 +0000194 // flag indicating whether the manager is considered alive
195 private volatile boolean isActive;
196
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000197 public void start( BundleContext bundleContext )
198 {
199 // track the log service using a ServiceTracker
Felix Meschberger85b355d2007-08-31 07:17:38 +0000200 logTracker = new ServiceTracker( bundleContext, LOG_SERVICE_NAME , null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000201 logTracker.open();
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000202
Felix Meschberger08282c32009-01-28 07:01:55 +0000203 // assign the log level
204 String logLevelProp = bundleContext.getProperty( CM_LOG_LEVEL );
205 if ( logLevelProp == null )
206 {
207 logLevel = CM_LOG_LEVEL_DEFAULT;
208 }
209 else
210 {
211 try
212 {
213 logLevel = Integer.parseInt( logLevelProp );
214 }
215 catch ( NumberFormatException nfe )
216 {
217 logLevel = CM_LOG_LEVEL_DEFAULT;
218 }
219 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000220
221 // set up some fields
222 this.bundleContext = bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000223
224 // configurationlistener support
225 configurationListenerTracker = new ServiceTracker( bundleContext, ConfigurationListener.class.getName(), null );
226 configurationListenerTracker.open();
Felix Meschbergere94b1572012-07-14 11:59:29 +0000227 syncConfigurationListenerTracker = new ServiceTracker( bundleContext,
228 SynchronousConfigurationListener.class.getName(), null );
229 syncConfigurationListenerTracker.open();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000230
231 // initialize the asynchonous updater thread
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000232 ThreadGroup tg = new ThreadGroup( "Configuration Admin Service" );
233 tg.setDaemon( true );
234 this.updateThread = new UpdateThread( this, tg, "CM Configuration Updater" );
235 this.eventThread = new UpdateThread( this, tg, "CM Event Dispatcher" );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000236
237 // set up the location (might throw IllegalArgumentException)
238 try
239 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000240 FilePersistenceManager fpm = new FilePersistenceManager( bundleContext, bundleContext
241 .getProperty( CM_CONFIG_DIR ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000242 Hashtable props = new Hashtable();
243 props.put( Constants.SERVICE_PID, fpm.getClass().getName() );
244 props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
245 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
246 props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
247 bundleContext.registerService( PersistenceManager.class.getName(), fpm, props );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000248
249 // setup dynamic configuration bindings
250 dynamicBindings = new DynamicBindings( bundleContext, fpm );
251 }
252 catch ( IOException ioe )
253 {
254 log( LogService.LOG_ERROR, "Failure setting up dynamic configuration bindings", ioe );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000255 }
256 catch ( IllegalArgumentException iae )
257 {
258 log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
259 }
260
261 // register as bundle and service listener
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000262 handleBundleEvents = true;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000263 bundleContext.addBundleListener( this );
264
265 // get all persistence managers to begin with
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000266 pmtCount = 1; // make sure to get the persistence managers at least once
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000267 persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
268 persistenceManagerTracker.open();
269
Felix Meschberger623f7142012-01-31 07:13:37 +0000270 // consider alive now (before clients use Configuration Admin
271 // service registered in the next step)
272 isActive = true;
273
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000274 // create and register configuration admin - start after PM tracker ...
275 ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
276 Hashtable props = new Hashtable();
277 props.put( Constants.SERVICE_PID, "org.apache.felix.cm.ConfigurationAdmin" );
278 props.put( Constants.SERVICE_DESCRIPTION, "Configuration Admin Service Specification 1.2 Implementation" );
279 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000280 configurationAdminRegistration = bundleContext.registerService( ConfigurationAdmin.class.getName(), caf, props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000281
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000282 // start handling ManagedService[Factory] services
283 managedServiceTracker = new ManagedServiceTracker(this);
284 managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this);
285
Felix Meschberger4b26df92011-02-01 12:41:45 +0000286 // start processing the event queues only after registering the service
287 // see FELIX-2813 for details
288 this.updateThread.start();
289 this.eventThread.start();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000290 }
291
292
293 public void stop( BundleContext bundleContext )
294 {
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000295
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000296 // stop handling bundle events immediately
297 handleBundleEvents = false;
298
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000299 // stop handling ManagedService[Factory] services
300 managedServiceFactoryTracker.close();
301 managedServiceTracker.close();
302
Felix Meschberger4b26df92011-02-01 12:41:45 +0000303 // stop queue processing before unregistering the service
304 // see FELIX-2813 for details
305 if ( updateThread != null )
306 {
307 updateThread.terminate();
308 }
309 if ( eventThread != null )
310 {
311 eventThread.terminate();
312 }
313
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000314 // immediately unregister the Configuration Admin before cleaning up
Felix Meschberger10568352009-01-15 08:57:11 +0000315 // clearing the field before actually unregistering the service
316 // prevents IllegalStateException in getServiceReference() if
317 // the field is not null but the service already unregistered
318 if (configurationAdminRegistration != null) {
319 ServiceRegistration reg = configurationAdminRegistration;
320 configurationAdminRegistration = null;
321 reg.unregister();
322 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000323
Felix Meschberger623f7142012-01-31 07:13:37 +0000324 // consider inactive after unregistering such that during
325 // unregistration the manager is still alive and can react
326 isActive = false;
327
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000328 // don't care for PersistenceManagers any more
329 persistenceManagerTracker.close();
330
331 // stop listening for events
332 bundleContext.removeBundleListener( this );
333
334 if ( configurationListenerTracker != null )
335 {
336 configurationListenerTracker.close();
337 }
338
Felix Meschbergere94b1572012-07-14 11:59:29 +0000339 if ( syncConfigurationListenerTracker != null )
340 {
341 syncConfigurationListenerTracker.close();
342 }
343
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000344 if ( logTracker != null )
345 {
346 logTracker.close();
347 }
348
Felix Meschberger6a698df2009-08-16 18:38:46 +0000349 // just ensure the configuration cache is empty
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000350 synchronized ( configurations )
351 {
352 configurations.clear();
353 }
354
Felix Meschberger6a698df2009-08-16 18:38:46 +0000355 // just ensure the factory cache is empty
356 synchronized ( factories )
357 {
358 factories.clear();
359 }
360
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000361 this.bundleContext = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000362 }
363
364
Felix Meschberger623f7142012-01-31 07:13:37 +0000365 /**
366 * Returns <code>true</code> if this manager is considered active.
367 */
368 boolean isActive()
369 {
370 return isActive;
371 }
372
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000373 public BundleContext getBundleContext()
374 {
375 return bundleContext;
376 }
Felix Meschberger623f7142012-01-31 07:13:37 +0000377
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000378 // ---------- Configuration caching support --------------------------------
379
380 ConfigurationImpl getCachedConfiguration( String pid )
381 {
382 synchronized ( configurations )
383 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000384 return configurations.get( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000385 }
386 }
387
388
Felix Meschberger6a698df2009-08-16 18:38:46 +0000389 ConfigurationImpl[] getCachedConfigurations()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000390 {
391 synchronized ( configurations )
392 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000393 return configurations.values().toArray(
Felix Meschberger6a698df2009-08-16 18:38:46 +0000394 new ConfigurationImpl[configurations.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000395 }
396 }
397
398
Felix Meschberger2941ef92007-08-20 13:15:16 +0000399 ConfigurationImpl cacheConfiguration( ConfigurationImpl configuration )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000400 {
401 synchronized ( configurations )
402 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000403 final String pid = configuration.getPidString();
404 final Object existing = configurations.get( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000405 if ( existing != null )
406 {
407 return ( ConfigurationImpl ) existing;
408 }
409
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000410 configurations.put( pid, configuration );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000411 return configuration;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000412 }
413 }
414
415
416 void removeConfiguration( ConfigurationImpl configuration )
417 {
418 synchronized ( configurations )
419 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000420 configurations.remove( configuration.getPidString() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000421 }
422 }
423
424
Felix Meschberger6a698df2009-08-16 18:38:46 +0000425 Factory getCachedFactory( String factoryPid )
426 {
427 synchronized ( factories )
428 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000429 return factories.get( factoryPid );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000430 }
431 }
432
433
434 Factory[] getCachedFactories()
435 {
436 synchronized ( factories )
437 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000438 return factories.values().toArray( new Factory[factories.size()] );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000439 }
440 }
441
442
443 void cacheFactory( Factory factory )
444 {
445 synchronized ( factories )
446 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000447 factories.put( factory.getFactoryPidString(), factory );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000448 }
449 }
450
451
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000452 // ---------- ConfigurationAdminImpl support
Felix Meschberger6a698df2009-08-16 18:38:46 +0000453
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000454 void setDynamicBundleLocation( final String pid, final String location )
455 {
456 if ( dynamicBindings != null )
457 {
458 try
459 {
460 dynamicBindings.putLocation( pid, location );
461 }
462 catch ( IOException ioe )
463 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000464 log( LogService.LOG_ERROR, "Failed storing dynamic configuration binding for {0} to {1}", new Object[]
465 { pid, location, ioe } );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000466 }
467 }
468 }
469
470
471 String getDynamicBundleLocation( final String pid )
472 {
473 if ( dynamicBindings != null )
474 {
475 return dynamicBindings.getLocation( pid );
476 }
477
478 return null;
479 }
480
481
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000482 ConfigurationImpl createFactoryConfiguration( String factoryPid, String location ) throws IOException
483 {
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000484 return cacheConfiguration( createConfiguration( createPid( factoryPid ), factoryPid, location ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000485 }
486
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000487 /**
488 * Returns a targeted configuration for the given service PID and
489 * the reference target service.
Felix Meschberger273985f2012-07-05 12:28:06 +0000490 * <p>
491 * A configuration returned has already been checked for visibility
492 * by the bundle registering the referenced service. Additionally,
493 * the configuration is also dynamically bound if needed.
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000494 *
495 * @param rawPid The raw service PID to get targeted configuration for.
496 * @param target The target <code>ServiceReference</code> to get
497 * configuration for.
498 * @return The best matching targeted configuration or <code>null</code>
499 * if there is no configuration at all.
500 * @throwss IOException if an error occurrs reading configurations
501 * from persistence.
502 */
503 ConfigurationImpl getTargetedConfiguration( final String rawPid, final ServiceReference target ) throws IOException
504 {
505 final Bundle serviceBundle = target.getBundle();
506 if ( serviceBundle != null )
507 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000508 // list of targeted PIDs to check
509 // (StringBuffer for pre-1.5 API compatibility)
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000510 final StringBuffer targetedPid = new StringBuffer( rawPid );
511 int i = 3;
512 String[] names = new String[4];
513 names[i--] = targetedPid.toString();
514 targetedPid.append( '|' ).append( serviceBundle.getSymbolicName() );
515 names[i--] = targetedPid.toString();
516 targetedPid.append( '|' ).append( TargetedPID.getBundleVersion( serviceBundle ) );
517 names[i--] = targetedPid.toString();
518 targetedPid.append( '|' ).append( serviceBundle.getLocation() );
519 names[i--] = targetedPid.toString();
520
521 for ( String candidate : names )
522 {
523 ConfigurationImpl config = getConfiguration( candidate );
Felix Meschbergercd5195f2012-07-05 17:17:45 +0000524 if ( config != null && !config.isDeleted() )
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000525 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000526 // check visibility to use and dynamically bind
527 if ( canReceive( serviceBundle, config.getBundleLocation() ) )
528 {
529 config.tryBindLocation( serviceBundle.getLocation() );
530 return config;
531 }
532
533 // CM 1.4 / 104.13.2.2 / 104.5.3
534 // act as if there is no configuration
535 log(
536 LogService.LOG_DEBUG,
537 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}; calling with null",
538 new Object[]
539 { config.getPid(), toString( target ), config.getBundleLocation() } );
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000540 }
541 }
542 }
Felix Meschberger273985f2012-07-05 12:28:06 +0000543 else
544 {
545 log( LogService.LOG_INFO,
546 "Service for PID {0} seems to already have been unregistered, not updating with configuration",
547 new Object[]
548 { rawPid } );
549 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000550
551 // service already unregistered, nothing to do really
552 return null;
553 }
554
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000555
Felix Meschbergerad949872011-11-16 10:34:54 +0000556 /**
557 * Returns the {@link ConfigurationImpl} with the given PID if
558 * available in the internal cache or from any persistence manager.
559 * Otherwise <code>null</code> is returned.
560 *
561 * @param pid The PID for which to return the configuration
562 * @return The configuration or <code>null</code> if non exists
563 * @throws IOException If an error occurrs reading from a persistence
564 * manager.
565 */
566 ConfigurationImpl getConfiguration( String pid ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000567 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000568 ConfigurationImpl config = getCachedConfiguration( pid );
569 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000570 {
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000571 log( LogService.LOG_DEBUG, "Found cached configuration {0} bound to {1}", new Object[]
572 { pid, config.getBundleLocation() } );
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000573
574 config.ensureFactoryConfigPersisted();
575
Felix Meschberger2941ef92007-08-20 13:15:16 +0000576 return config;
577 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000578
Felix Meschberger2941ef92007-08-20 13:15:16 +0000579 PersistenceManager[] pmList = getPersistenceManagers();
580 for ( int i = 0; i < pmList.length; i++ )
581 {
582 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000583 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000584 Dictionary props = pmList[i].load( pid );
585 config = new ConfigurationImpl( this, pmList[i], props );
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000586 log( LogService.LOG_DEBUG, "Found existing configuration {0} bound to {1}", new Object[]
587 { pid, config.getBundleLocation() } );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000588 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000589 }
590 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000591
Felix Meschberger2941ef92007-08-20 13:15:16 +0000592 // neither the cache nor any persistence manager has configuration
593 return null;
594 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000595
596
Felix Meschbergerad949872011-11-16 10:34:54 +0000597 /**
598 * Creates a regular (non-factory) configuration for the given PID
599 * setting the bundle location accordingly.
600 * <p>
601 * This method assumes the configuration to not exist yet and will
602 * create it without further checking.
603 *
604 * @param pid The PID of the new configuration
605 * @param bundleLocation The location to set on the new configuration.
606 * This may be <code>null</code> to not bind the configuration
607 * yet.
608 * @return The new configuration persisted in the first persistence
609 * manager.
610 * @throws IOException If an error occurrs writing the configuration
611 * to the persistence.
612 */
613 ConfigurationImpl createConfiguration( String pid, String bundleLocation ) throws IOException
Felix Meschberger2941ef92007-08-20 13:15:16 +0000614 {
615 // check for existing (cached or persistent) configuration
Felix Meschbergerad949872011-11-16 10:34:54 +0000616 ConfigurationImpl config = getConfiguration( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000617 if ( config != null )
618 {
619 return config;
620 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000621
Felix Meschberger2941ef92007-08-20 13:15:16 +0000622 // else create new configuration also setting the bundle location
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000623 // and cache the new configuration
624 config = createConfiguration( pid, null, bundleLocation );
625 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000626 }
627
628
629 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
630 throws IOException, InvalidSyntaxException
631 {
632 Filter filter = null;
633 if ( filterString != null )
634 {
635 filter = bundleContext.createFilter( filterString );
636 }
637
Felix Meschberger4f269292011-10-21 13:52:31 +0000638 log( LogService.LOG_DEBUG, "Listing configurations matching {0}", new Object[]
639 { filterString } );
640
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000641 List configList = new ArrayList();
642
643 PersistenceManager[] pmList = getPersistenceManagers();
644 for ( int i = 0; i < pmList.length; i++ )
645 {
646 Enumeration configs = pmList[i].getDictionaries();
647 while ( configs.hasMoreElements() )
648 {
649 Dictionary config = ( Dictionary ) configs.nextElement();
650
651 // ignore non-Configuration dictionaries
Felix Meschberger86a0d172007-07-04 07:15:01 +0000652 String pid = ( String ) config.get( Constants.SERVICE_PID );
653 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000654 {
655 continue;
656 }
657
Felix Meschberger007c50e2011-10-20 12:39:38 +0000658 // CM 1.4 / 104.13.2.3 Permission required
659 if ( !configurationAdmin.hasPermission( ( String ) config
660 .get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000661 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000662 log(
663 LogService.LOG_DEBUG,
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000664 "Omitting configuration {0}: No permission for bundle {1} on configuration bound to {2}",
Felix Meschberger4f269292011-10-21 13:52:31 +0000665 new Object[]
666 { config.get( Constants.SERVICE_PID ), configurationAdmin.getBundle().getLocation(),
667 config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000668 continue;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000669 }
670
671 // check filter
672 if ( filter == null || filter.match( config ) )
673 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000674 // ensure the service.pid and returned a cached config if available
675 ConfigurationImpl cfg = getCachedConfiguration( pid );
676 if ( cfg == null )
677 {
678 cfg = new ConfigurationImpl( this, pmList[i], config );
679 }
680
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000681 // FELIX-611: Ignore configuration objects without props
682 if ( !cfg.isNew() )
683 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000684 log( LogService.LOG_DEBUG, "Adding configuration {0}", new Object[]
685 { config.get( Constants.SERVICE_PID ) } );
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000686 configList.add( cfg );
687 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000688 else
689 {
690 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Is new", new Object[]
691 { config.get( Constants.SERVICE_PID ) } );
692 }
693 } else {
694 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Does not match filter", new Object[]
695 { config.get( Constants.SERVICE_PID ) } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000696 }
697 }
698 }
699
Felix Meschberger8faceff2007-07-04 07:19:48 +0000700 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000701 .size()] );
702 }
703
704
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000705 void deleted( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000706 {
707 // remove the configuration from the cache
708 removeConfiguration( config );
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000709 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000710 updateThread.schedule( new DeleteConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000711 log( LogService.LOG_DEBUG, "DeleteConfiguration({0}) scheduled", new Object[]
712 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000713 }
714
715
Felix Meschbergerce67d732009-08-20 06:26:35 +0000716 void updated( ConfigurationImpl config, boolean fireEvent )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000717 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000718 if ( fireEvent )
719 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000720 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000721 }
722 updateThread.schedule( new UpdateConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000723 log( LogService.LOG_DEBUG, "UpdateConfiguration({0}) scheduled", new Object[]
724 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000725 }
726
727
Felix Meschberger007c50e2011-10-20 12:39:38 +0000728 void locationChanged( ConfigurationImpl config, String oldLocation )
729 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000730 fireConfigurationEvent( ConfigurationEvent.CM_LOCATION_CHANGED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger35658d52011-10-20 21:43:58 +0000731 if ( oldLocation != null && !config.isNew() )
Felix Meschberger007c50e2011-10-20 12:39:38 +0000732 {
733 updateThread.schedule( new LocationChanged( config, oldLocation ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000734 log( LogService.LOG_DEBUG, "LocationChanged({0}, {1}=>{2}) scheduled", new Object[]
735 { config.getPid(), oldLocation, config.getBundleLocation() } );
Felix Meschberger35658d52011-10-20 21:43:58 +0000736 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000737 else
Felix Meschberger35658d52011-10-20 21:43:58 +0000738 {
739 log( LogService.LOG_DEBUG,
Felix Meschberger4f269292011-10-21 13:52:31 +0000740 "LocationChanged not scheduled for {0} (old location is null or configuration is new)", new Object[]
741 { config.getPid() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000742 }
743 }
744
745
Felix Meschberger66423332007-08-22 08:46:34 +0000746 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000747 {
Felix Meschbergere94b1572012-07-14 11:59:29 +0000748 // prevent event senders
749 FireConfigurationEvent asyncSender = new FireConfigurationEvent( this.configurationListenerTracker, type, pid,
750 factoryPid );
751 FireConfigurationEvent syncSender = new FireConfigurationEvent( this.syncConfigurationListenerTracker, type,
752 pid, factoryPid );
753
754 // send synchronous events
755 if ( syncSender.hasConfigurationEventListeners() )
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000756 {
Felix Meschbergere94b1572012-07-14 11:59:29 +0000757 syncSender.run();
758 }
759 else
760 {
761 log( LogService.LOG_DEBUG, "No SynchronousConfigurationListeners to send {0} event to.", new Object[]
762 { syncSender.getTypeName() } );
763 }
764
765 // schedule asynchronous events
766 if ( asyncSender.hasConfigurationEventListeners() )
767 {
768 eventThread.schedule( asyncSender );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000769 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000770 else
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000771 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000772 log( LogService.LOG_DEBUG, "No ConfigurationListeners to send {0} event to.", new Object[]
Felix Meschbergere94b1572012-07-14 11:59:29 +0000773 { asyncSender.getTypeName() } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000774 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000775 }
776
777
778 // ---------- BundleListener -----------------------------------------------
779
780 public void bundleChanged( BundleEvent event )
781 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000782 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000783 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000784 final String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000785
Felix Meschberger6a698df2009-08-16 18:38:46 +0000786 // we only reset dynamic bindings, which are only present in
787 // cached configurations, hence only consider cached configs here
788 final ConfigurationImpl[] configs = getCachedConfigurations();
789 for ( int i = 0; i < configs.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000790 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000791 final ConfigurationImpl cfg = configs[i];
Felix Meschberger41cce522009-08-19 05:54:40 +0000792 if ( location.equals( cfg.getDynamicBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000793 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000794 cfg.setDynamicBundleLocation( null, true );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000795 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000796 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000797 }
798 }
799
800
801 // ---------- internal -----------------------------------------------------
802
803 private PersistenceManager[] getPersistenceManagers()
804 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000805 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
806 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000807 {
808
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000809 List pmList = new ArrayList();
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000810 PersistenceManager[] pm;
811
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000812 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
813 if ( refs == null || refs.length == 0 )
814 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000815 pm = new PersistenceManager[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000816 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000817 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000818 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000819 // sort the references according to the cmRanking property
Felix Meschberger007c50e2011-10-20 12:39:38 +0000820 if ( refs.length > 1 )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000821 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000822 Arrays.sort( refs, RankingComparator.SRV_RANKING );
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000823 }
824
825 // create the service array from the sorted set of referenecs
Felix Meschberger007c50e2011-10-20 12:39:38 +0000826 for ( int i = 0; i < refs.length; i++ )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000827 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000828 Object service = persistenceManagerTracker.getService( refs[i] );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000829 if ( service != null )
830 {
Felix Meschbergera86cdfc2010-08-25 09:32:36 +0000831 pmList.add( new CachingPersistenceManagerProxy( ( PersistenceManager ) service ) );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000832 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000833 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000834
835 pm = ( PersistenceManager[] ) pmList.toArray( new PersistenceManager[pmList.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000836 }
837
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000838 pmtCount = pm.length;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000839 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000840 }
841
842 return persistenceManagers;
843 }
844
845
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000846 private ServiceReference getServiceReference()
847 {
848 ServiceRegistration reg = configurationAdminRegistration;
Felix Meschberger0770cad2012-06-11 12:36:52 +0000849 if (reg != null) {
850 return reg.getReference();
851 }
852
853 // probably called for firing an event during service registration
854 // since we didn't get the service registration yet we use the
855 // service registry to get our service reference
856 BundleContext context = bundleContext;
857 if ( context != null )
858 {
859 try
860 {
861 ServiceReference[] refs = context.getServiceReferences( ConfigurationAdmin.class.getName(), null );
862 if ( refs != null )
863 {
864 for ( int i = 0; i < refs.length; i++ )
865 {
866 if ( refs[i].getBundle().getBundleId() == context.getBundle().getBundleId() )
867 {
868 return refs[i];
869 }
870 }
871 }
872 }
873 catch ( InvalidSyntaxException e )
874 {
875 // unexpected since there is no filter
876 }
877 }
878
879 // service references
880 return null;
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000881 }
882
883
Felix Meschberger05d89e12011-11-03 23:37:10 +0000884 /**
885 * Configures the ManagedService and returns the service.pid
886 * service property as a String[], which may be <code>null</code> if
887 * the ManagedService does not have such a property.
888 */
Felix Meschberger05d89e12011-11-03 23:37:10 +0000889 /**
890 * Configures the ManagedServiceFactory and returns the service.pid
891 * service property as a String[], which may be <code>null</code> if
892 * the ManagedServiceFactory does not have such a property.
893 */
Felix Meschberger382a19b2012-07-03 09:45:14 +0000894 /**
895 * Schedules the configuration of the referenced service with
896 * configuration for the given PID.
897 *
Felix Meschberger273985f2012-07-05 12:28:06 +0000898 * @param pid The list of service PID of the configurations to be
899 * provided to the referenced service.
Felix Meschberger382a19b2012-07-03 09:45:14 +0000900 * @param sr The <code>ServiceReference</code> to the service
901 * to be configured.
902 * @param factory <code>true</code> If the service is considered to
903 * be a <code>ManagedServiceFactory</code>. Otherwise the service
904 * is considered to be a <code>ManagedService</code>.
905 */
Felix Meschberger273985f2012-07-05 12:28:06 +0000906 public void configure( String[] pid, ServiceReference sr, final boolean factory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000907 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000908 if ( this.isLogEnabled( LogService.LOG_DEBUG ) )
909 {
910 this.log( LogService.LOG_DEBUG, "configure(ManagedService {0})", new Object[]
911 { toString( sr ) } );
912 }
913
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000914 Runnable r;
915 if ( factory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000916 {
Felix Meschberger382a19b2012-07-03 09:45:14 +0000917 r = new ManagedServiceFactoryUpdate( pid, sr );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000918 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000919 else
920 {
Felix Meschberger382a19b2012-07-03 09:45:14 +0000921 r = new ManagedServiceUpdate( pid, sr );
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000922 }
923 updateThread.schedule( r );
924 log( LogService.LOG_DEBUG, "[{0}] scheduled", new Object[]
925 { r } );
Felix Meschberger851c6412009-08-16 18:43:26 +0000926 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000927
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000928
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000929 /**
930 * Factory method to create a new configuration object. The configuration
931 * object returned is not stored in configuration cache and only persisted
932 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000933 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000934 * @param pid
935 * The PID of the new configuration object. Must not be
936 * <code>null</code>.
937 * @param factoryPid
938 * The factory PID of the new configuration. Not
Felix Meschberger6a698df2009-08-16 18:38:46 +0000939 * <code>null</code> if the new configuration object belongs to a
940 * factory. The configuration object will not be persisted if
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000941 * this parameter is not <code>null</code>.
942 * @param bundleLocation
943 * The bundle location of the bundle to which the configuration
Felix Meschberger6a698df2009-08-16 18:38:46 +0000944 * belongs or <code>null</code> if the configuration is not bound
945 * yet.
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000946 * @return The new configuration object
947 * @throws IOException
948 * May be thrown if an error occurrs persisting the new
949 * configuration object.
950 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000951 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000952 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000953 log( LogService.LOG_DEBUG, "createConfiguration({0}, {1}, {2})", new Object[]
954 { pid, factoryPid, bundleLocation } );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000955 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000956 }
957
958
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000959 /**
960 * Returns a list of {@link Factory} instances according to the
961 * Configuration Admin 1.5 specification for targeted PIDs (Section
962 * 104.3.2)
963 *
964 * @param rawFactoryPid The raw factory PID without any targetting.
965 * @param target The <code>ServiceReference</code> of the service to
966 * be supplied with targeted configuration.
967 * @return A list of {@link Factory} instances as listed above. This
968 * list will always at least include an instance for the
969 * <code>rawFactoryPid</code>. Other instances are only included
970 * if existing.
971 * @throws IOException If an error occurrs reading any of the
972 * {@link Factory} instances from persistence
973 */
974 List<Factory> getTargetedFactories( final String rawFactoryPid, final ServiceReference target ) throws IOException
975 {
976 LinkedList<Factory> factories = new LinkedList<Factory>();
977
978 final Bundle serviceBundle = target.getBundle();
979 if ( serviceBundle != null )
980 {
981 // for pre-1.5 API compatibility
982 final StringBuffer targetedPid = new StringBuffer( rawFactoryPid );
983 factories.add( getOrCreateFactory( targetedPid.toString() ) );
984
985 targetedPid.append( '|' ).append( serviceBundle.getSymbolicName() );
986 Factory f = getFactory( targetedPid.toString() );
987 if ( f != null )
988 {
989 factories.add( 0, f );
990 }
991
992 targetedPid.append( '|' ).append( TargetedPID.getBundleVersion( serviceBundle ) );
993 f = getFactory( targetedPid.toString() );
994 if ( f != null )
995 {
996 factories.add( 0, f );
997 }
998
999 targetedPid.append( '|' ).append( serviceBundle.getLocation() );
1000 f = getFactory( targetedPid.toString() );
1001 if ( f != null )
1002 {
1003 factories.add( 0, f );
1004 }
1005 }
1006
1007 return factories;
1008 }
1009
1010
1011 /**
1012 * Gets the factory with the exact identifier from the cached or from
1013 * the persistence managers. If no factory exists already one is
1014 * created and cached.
1015 *
1016 * @param factoryPid The PID of the {@link Factory} to return
1017 * @return The existing or newly created {@link Factory}
1018 * @throws IOException If an error occurrs reading the factory from
1019 * a {@link PersistenceManager}
1020 */
1021 Factory getOrCreateFactory( String factoryPid ) throws IOException
1022 {
1023 Factory factory = getFactory( factoryPid );
1024 if ( factory != null )
1025 {
1026 return factory;
1027 }
1028
1029 return createFactory( factoryPid );
1030 }
1031
1032
1033 /**
1034 * Gets the factory with the exact identifier from the cached or from
1035 * the persistence managers. If no factory exists <code>null</code>
1036 * is returned.
1037 *
1038 * @param factoryPid The PID of the {@link Factory} to return
1039 * @return The existing {@link Factory} or <code>null</code>
1040 * @throws IOException If an error occurrs reading the factory from
1041 * a {@link PersistenceManager}
1042 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001043 Factory getFactory( String factoryPid ) throws IOException
1044 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001045 // check for cached factory
Felix Meschbergerf4631322008-03-10 12:32:35 +00001046 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001047 if ( factory != null )
1048 {
1049 return factory;
1050 }
1051
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001052 // try to load factory from persistence
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001053 PersistenceManager[] pmList = getPersistenceManagers();
1054 for ( int i = 0; i < pmList.length; i++ )
1055 {
1056 if ( Factory.exists( pmList[i], factoryPid ) )
1057 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +00001058 factory = Factory.load( this, pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001059 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001060 return factory;
1061 }
1062 }
1063
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001064 // no existing factory
1065 return null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001066 }
1067
1068
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001069 /**
1070 * Creates a new factory with the given <code>factoryPid</code>.
1071 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001072 Factory createFactory( String factoryPid )
1073 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +00001074 Factory factory = new Factory( this, getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001075 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001076 return factory;
1077 }
1078
1079
Felix Meschberger2941ef92007-08-20 13:15:16 +00001080 /**
1081 * Calls the registered configuration plugins on the given configuration
Felix Meschberger273985f2012-07-05 12:28:06 +00001082 * properties from the given configuration object.
1083 * <p>
1084 * The plugins to be called are selected as <code>ConfigurationPlugin</code>
1085 * services registered with a <code>cm.target</code> property set to
1086 * <code>*</code> or the factory PID of the configuration (for factory
1087 * configurations) or the PID of the configuration (for non-factory
1088 * configurations).
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001089 *
Felix Meschberger41cce522009-08-19 05:54:40 +00001090 * @param props The configuraiton properties run through the registered
Felix Meschberger273985f2012-07-05 12:28:06 +00001091 * ConfigurationPlugin services. This must not be
1092 * <code>null</code>.
Felix Meschberger2941ef92007-08-20 13:15:16 +00001093 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001094 * is to be updated with configuration
Felix Meschberger273985f2012-07-05 12:28:06 +00001095 * @param configPid The PID of the configuration object whose properties
1096 * are to be augmented
1097 * @param factoryPid the factory PID of the configuration object whose
1098 * properties are to be augmented. This is non-<code>null</code>
1099 * only for a factory configuration.
Felix Meschberger2941ef92007-08-20 13:15:16 +00001100 */
Felix Meschberger273985f2012-07-05 12:28:06 +00001101 public void callPlugins( final Dictionary props, final ServiceReference sr, final String configPid,
1102 final String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001103 {
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001104 ServiceReference[] plugins = null;
1105 try
1106 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001107 final String targetPid = (factoryPid == null) ? configPid : factoryPid;
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001108 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001109 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001110 }
1111 catch ( InvalidSyntaxException ise )
1112 {
1113 // no filter, no exception ...
1114 }
1115
1116 // abort early if there are no plugins
1117 if ( plugins == null || plugins.length == 0 )
1118 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001119 return;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001120 }
1121
1122 // sort the plugins by their service.cmRanking
Felix Meschberger007c50e2011-10-20 12:39:38 +00001123 if ( plugins.length > 1 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001124 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001125 Arrays.sort( plugins, RankingComparator.CM_RANKING );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001126 }
1127
1128 // call the plugins in order
Felix Meschberger007c50e2011-10-20 12:39:38 +00001129 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001130 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001131 ServiceReference pluginRef = plugins[i];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001132 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001133 if ( plugin != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001134 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001135 try
1136 {
1137 plugin.modifyConfiguration( sr, props );
1138 }
1139 catch ( Throwable t )
1140 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001141 log( LogService.LOG_ERROR, "Unexpected problem calling configuration plugin {0}", new Object[]
1142 { toString( pluginRef ), t } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001143 }
1144 finally
1145 {
1146 // ensure ungetting the plugin
1147 bundleContext.ungetService( pluginRef );
1148 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001149 ConfigurationImpl.setAutoProperties( props, configPid, factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001150 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001151 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001152 }
1153
1154
1155 /**
1156 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001157 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001158 * @param factoryPid
1159 * @return
1160 */
1161 private static String createPid( String factoryPid )
1162 {
Felix Meschberger417f66c2011-02-04 11:25:23 +00001163 Random ng = numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001164 if ( ng == null )
1165 {
Felix Meschberger417f66c2011-02-04 11:25:23 +00001166 // FELIX-2771 Secure Random not available on Mika
1167 try
1168 {
1169 ng = new SecureRandom();
1170 }
1171 catch ( Throwable t )
1172 {
1173 // fall back to Random
1174 ng = new Random();
1175 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001176 }
1177
1178 byte[] randomBytes = new byte[16];
1179 ng.nextBytes( randomBytes );
1180 randomBytes[6] &= 0x0f; /* clear version */
1181 randomBytes[6] |= 0x40; /* set to version 4 */
1182 randomBytes[8] &= 0x3f; /* clear variant */
1183 randomBytes[8] |= 0x80; /* set to IETF variant */
1184
1185 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
1186
1187 // prefix the new pid with the factory pid
1188 buf.append( factoryPid ).append( "." );
1189
1190 // serialize the UUID into the buffer
1191 for ( int i = 0; i < randomBytes.length; i++ )
1192 {
1193
1194 if ( i == 4 || i == 6 || i == 8 || i == 10 )
1195 {
1196 buf.append( '-' );
1197 }
1198
1199 int val = randomBytes[i] & 0xff;
1200 buf.append( Integer.toHexString( val >> 4 ) );
1201 buf.append( Integer.toHexString( val & 0xf ) );
1202 }
1203
1204 return buf.toString();
1205 }
1206
1207
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001208 public boolean isLogEnabled( int level )
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001209 {
1210 return level <= logLevel;
1211 }
1212
1213
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001214 public void log( int level, String format, Object[] args )
Felix Meschberger4f269292011-10-21 13:52:31 +00001215 {
1216 if ( isLogEnabled( level ) )
1217 {
1218 Throwable throwable = null;
1219 String message = format;
1220
1221 if ( args != null && args.length > 0 )
1222 {
1223 if ( args[args.length - 1] instanceof Throwable )
1224 {
1225 throwable = ( Throwable ) args[args.length - 1];
1226 }
1227 message = MessageFormat.format( format, args );
1228 }
1229
1230 log( level, message, throwable );
1231 }
1232 }
1233
1234
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001235 public void log( int level, String message, Throwable t )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001236 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001237 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +00001238 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001239 if ( log != null )
1240 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +00001241 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001242 return;
1243 }
1244
Felix Meschberger08282c32009-01-28 07:01:55 +00001245 // Otherwise only log if more serious than the configured level
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001246 if ( isLogEnabled( level ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001247 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001248 String code;
1249 switch ( level )
1250 {
1251 case LogService.LOG_INFO:
1252 code = "*INFO *";
1253 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001254
Felix Meschberger08282c32009-01-28 07:01:55 +00001255 case LogService.LOG_WARNING:
1256 code = "*WARN *";
1257 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001258
Felix Meschberger08282c32009-01-28 07:01:55 +00001259 case LogService.LOG_ERROR:
1260 code = "*ERROR*";
1261 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001262
Felix Meschberger08282c32009-01-28 07:01:55 +00001263 case LogService.LOG_DEBUG:
1264 default:
1265 code = "*DEBUG*";
1266 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001267
Felix Meschberger08282c32009-01-28 07:01:55 +00001268 System.err.println( code + " " + message );
1269 if ( t != null )
1270 {
1271 t.printStackTrace( System.err );
1272 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001273 }
1274 }
1275
Felix Meschberger851c6412009-08-16 18:43:26 +00001276
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001277 public static String toString( ServiceReference ref )
Felix Meschberger41cce522009-08-19 05:54:40 +00001278 {
1279 String[] ocs = ( String[] ) ref.getProperty( "objectClass" );
Felix Meschberger382a19b2012-07-03 09:45:14 +00001280 StringBuffer buf = new StringBuffer( "[" );
Felix Meschberger41cce522009-08-19 05:54:40 +00001281 for ( int i = 0; i < ocs.length; i++ )
1282 {
Felix Meschberger382a19b2012-07-03 09:45:14 +00001283 buf.append( ocs[i] );
Felix Meschberger41cce522009-08-19 05:54:40 +00001284 if ( i < ocs.length - 1 )
Felix Meschberger382a19b2012-07-03 09:45:14 +00001285 buf.append( ", " );
Felix Meschberger41cce522009-08-19 05:54:40 +00001286 }
1287
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001288 buf.append( ", id=" ).append( ref.getProperty( Constants.SERVICE_ID ) );
1289
1290 Bundle provider = ref.getBundle();
1291 if ( provider != null )
1292 {
1293 buf.append( ", bundle=" ).append( provider.getBundleId() );
Felix Meschberger0135b322011-11-16 12:30:22 +00001294 buf.append( '/' ).append( provider.getLocation() );
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001295 }
1296 else
1297 {
1298 buf.append( ", unregistered" );
1299 }
1300
1301 buf.append( "]" );
1302 return buf.toString();
Felix Meschberger41cce522009-08-19 05:54:40 +00001303 }
1304
Felix Meschbergerce67d732009-08-20 06:26:35 +00001305
Felix Meschberger007c50e2011-10-20 12:39:38 +00001306 /**
1307 * Checks whether the bundle is allowed to receive the configuration
1308 * with the given location binding.
1309 * <p>
1310 * This method implements the logic defined CM 1.4 / 104.4.1:
1311 * <ul>
1312 * <li>If the location is <code>null</code> (the configuration is not
1313 * bound yet), assume the bundle is allowed</li>
1314 * <li>If the location is a single location (no leading "?"), require
1315 * the bundle's location to match</li>
1316 * <li>If the location is a multi-location (leading "?"), assume the
1317 * bundle is allowed if there is no security manager. If there is a
1318 * security manager, check whether the bundle has "target" permission
1319 * on this location.</li>
1320 * </ul>
1321 */
1322 boolean canReceive( final Bundle bundle, final String location )
1323 {
1324 if ( location == null )
1325 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001326 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration=(unbound)", new Object[]
Felix Meschberger61207232011-11-17 10:06:45 +00001327 { bundle.getLocation() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001328 return true;
1329 }
1330 else if ( location.startsWith( "?" ) )
1331 {
1332 // multi-location
1333 if ( System.getSecurityManager() != null )
1334 {
Felix Meschberger61207232011-11-17 10:06:45 +00001335 final boolean hasPermission = bundle.hasPermission( new ConfigurationPermission( location,
1336 ConfigurationPermission.TARGET ) );
1337 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2} (SecurityManager check)",
1338 new Object[]
1339 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1340 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001341 }
Felix Meschberger61207232011-11-17 10:06:45 +00001342
1343 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration={1} (no SecurityManager)",
1344 new Object[]
1345 { bundle.getLocation(), location } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001346 return true;
1347 }
1348 else
1349 {
1350 // single location, must match
Felix Meschberger61207232011-11-17 10:06:45 +00001351 final boolean hasPermission = location.equals( bundle.getLocation() );
1352 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2}", new Object[]
1353 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1354 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001355 }
1356 }
1357
Felix Meschberger61207232011-11-17 10:06:45 +00001358
Felix Meschberger007c50e2011-10-20 12:39:38 +00001359 // ---------- inner classes
1360
Felix Meschberger007c50e2011-10-20 12:39:38 +00001361 /**
1362 * The <code>ManagedServiceUpdate</code> updates a freshly registered
1363 * <code>ManagedService</code> with a specific configuration. If a
1364 * ManagedService is registered with multiple PIDs an instance of this
1365 * class is used for each registered PID.
1366 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001367 private class ManagedServiceUpdate implements Runnable
1368 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001369 private final String[] pids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001370
Felix Meschberger41cce522009-08-19 05:54:40 +00001371 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001372
Felix Meschberger273985f2012-07-05 12:28:06 +00001373 ManagedServiceUpdate( String[] pids, ServiceReference sr )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001374 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001375 this.pids = pids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001376 this.sr = sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001377 }
1378
1379
1380 public void run()
1381 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001382 for ( String pid : this.pids )
1383 {
1384 try
1385 {
1386 final ConfigurationImpl config = getTargetedConfiguration( pid, this.sr );
1387 provide( pid, config );
1388 }
1389 catch ( IOException ioe )
1390 {
1391 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1392 { pid, ioe } );
1393 }
1394 catch ( Exception e )
1395 {
1396 log( LogService.LOG_ERROR, "Unexpected problem providing configuration {0} to service {1}",
1397 new Object[]
1398 { pid, ConfigurationManager.toString( this.sr ), e } );
1399 }
1400 }
1401 }
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001402
Felix Meschberger273985f2012-07-05 12:28:06 +00001403
1404 private void provide(final String servicePid, final ConfigurationImpl config)
1405 {
1406 // check configuration
1407 final TargetedPID configPid;
1408 final Dictionary properties;
1409 final long revision;
Felix Meschberger41cce522009-08-19 05:54:40 +00001410 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001411 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001412 synchronized ( config )
Felix Meschberger41243192009-01-14 19:59:58 +00001413 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001414 configPid = config.getPid();
1415 properties = config.getProperties( true );
1416 revision = config.getRevision();
Felix Meschberger41243192009-01-14 19:59:58 +00001417 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001418 }
1419 else
1420 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001421 // 104.5.3 ManagedService.updated must be called with null
1422 // if no configuration is available
Felix Meschberger273985f2012-07-05 12:28:06 +00001423 configPid = new TargetedPID( servicePid );
Felix Meschberger41cce522009-08-19 05:54:40 +00001424 properties = null;
Felix Meschberger273985f2012-07-05 12:28:06 +00001425 revision = -1;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001426 }
1427
Felix Meschberger273985f2012-07-05 12:28:06 +00001428 log( LogService.LOG_DEBUG, "Updating service {0} with configuration {1}@{2}", new Object[]
1429 { servicePid, configPid, new Long( revision ) } );
1430
1431 managedServiceTracker.provideConfiguration( sr, configPid, null, properties, revision);
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001432 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001433
Felix Meschberger432e3872008-03-07 14:58:57 +00001434 public String toString()
1435 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001436 return "ManagedService Update: pid=" + Arrays.asList( pids );
Felix Meschberger432e3872008-03-07 14:58:57 +00001437 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001438 }
1439
Felix Meschberger007c50e2011-10-20 12:39:38 +00001440 /**
1441 * The <code>ManagedServiceFactoryUpdate</code> updates a freshly
1442 * registered <code>ManagedServiceFactory</code> with a specific
1443 * configuration. If a ManagedServiceFactory is registered with
1444 * multiple PIDs an instance of this class is used for each registered
1445 * PID.
1446 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001447 private class ManagedServiceFactoryUpdate implements Runnable
1448 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001449 private final String[] factoryPids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001450
Felix Meschberger41cce522009-08-19 05:54:40 +00001451 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001452
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001453
Felix Meschberger273985f2012-07-05 12:28:06 +00001454 ManagedServiceFactoryUpdate( String[] factoryPids, ServiceReference sr )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001455 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001456 this.factoryPids = factoryPids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001457 this.sr = sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001458 }
1459
1460
1461 public void run()
1462 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001463 for ( String factoryPid : this.factoryPids )
1464 {
1465
1466 List<Factory> factories = null;
1467 try
1468 {
1469 factories = getTargetedFactories( factoryPid, sr );
1470 for ( Factory factory : factories )
1471 {
1472 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
1473 {
1474 final String pid = ( String ) pi.next();
1475 ConfigurationImpl cfg;
1476 try
1477 {
1478 cfg = getConfiguration( pid );
1479 }
1480 catch ( IOException ioe )
1481 {
1482 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1483 { pid, ioe } );
1484 continue;
1485 }
1486
1487 // sanity check on the configuration
1488 if ( cfg == null )
1489 {
1490 log( LogService.LOG_ERROR,
1491 "Configuration {0} referred to by factory {1} does not exist", new Object[]
1492 { pid, factoryPid } );
1493 factory.removePID( pid );
1494 factory.storeSilently();
1495 continue;
1496 }
1497 else if ( cfg.isNew() )
1498 {
1499 // Configuration has just been created but not yet updated
1500 // we currently just ignore it and have the update mechanism
1501 // provide the configuration to the ManagedServiceFactory
1502 // As of FELIX-612 (not storing new factory configurations)
1503 // this should not happen. We keep this for added stability
1504 // but raise the logging level to error.
1505 log( LogService.LOG_ERROR, "Ignoring new configuration pid={0}", new Object[]
1506 { pid } );
1507 continue;
1508 }
1509
1510 /*
1511 * this code would catch targeted factory PIDs;
1512 * since this is not expected any way, we can
1513 * leave this out
1514 */
1515 /*
1516 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1517 {
1518 log( LogService.LOG_ERROR,
1519 "Configuration {0} referred to by factory {1} seems to belong to factory {2}",
1520 new Object[]
1521 { pid, factoryPid, cfg.getFactoryPid() } );
1522 factory.removePID( pid );
1523 factory.storeSilently();
1524 continue;
1525 }
1526 */
1527
1528 provide( factoryPid, cfg );
1529 }
1530 }
1531 }
1532 catch ( IOException ioe )
1533 {
1534 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID {0}", new Object[]
1535 { factoryPid, ioe } );
1536 }
1537 }
1538 }
1539
1540
1541 private void provide(final String factoryPid, final ConfigurationImpl config) {
1542
1543 final Dictionary rawProperties;
1544 final long revision;
1545 synchronized ( config )
1546 {
1547 rawProperties = config.getProperties( true );
1548 revision = config.getRevision();
1549 }
1550
1551 log( LogService.LOG_DEBUG, "Updating service {0} with configuration {1}/{2}@{3}", new Object[]
1552 { factoryPid, config.getFactoryPid(), config.getPid(), new Long( revision ) } );
1553
1554 // CM 1.4 / 104.13.2.1
1555 final Bundle serviceBundle = this.sr.getBundle();
Felix Meschberger41243192009-01-14 19:59:58 +00001556 if ( serviceBundle == null )
1557 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001558 log(
1559 LogService.LOG_INFO,
1560 "ManagedServiceFactory for factory PID {0} seems to already have been unregistered, not updating with factory",
1561 new Object[]
1562 { factoryPid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001563 return;
1564 }
1565
Felix Meschberger273985f2012-07-05 12:28:06 +00001566 if ( !canReceive( serviceBundle, config.getBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001567 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001568 log( LogService.LOG_ERROR,
1569 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001570 new Object[]
Felix Meschberger273985f2012-07-05 12:28:06 +00001571 { config.getPid(), ConfigurationManager.toString( sr ), config.getBundleLocation() } );
1572
1573 // no service, really, bail out
1574 return;
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001575 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001576
1577 // 104.4.2 Dynamic Binding
1578 config.tryBindLocation( serviceBundle.getLocation() );
1579
1580 // update the service with the configuration (if non-null)
1581 if ( rawProperties != null )
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001582 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001583 log( LogService.LOG_DEBUG, "{0}: Updating configuration pid={1}", new Object[]
1584 { ConfigurationManager.toString( sr ), config.getPid() } );
1585 managedServiceFactoryTracker.provideConfiguration( sr, config.getPid(), config.getFactoryPid(),
1586 rawProperties, revision );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001587 }
1588 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001589
1590
Felix Meschberger432e3872008-03-07 14:58:57 +00001591 public String toString()
1592 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001593 return "ManagedServiceFactory Update: factoryPid=" + Arrays.asList( this.factoryPids );
Felix Meschberger432e3872008-03-07 14:58:57 +00001594 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001595 }
1596
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001597 private abstract class ConfigurationProvider<T> implements Runnable
1598 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001599
1600 protected final ConfigurationImpl config;
1601 protected final long revision;
1602 protected final Dictionary<String, ?> properties;
1603 protected final BaseTracker<T> helper;
1604
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001605
1606 protected ConfigurationProvider( final ConfigurationImpl config )
1607 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001608 synchronized ( config )
1609 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001610 this.config = config;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001611 this.revision = config.getRevision();
1612 this.properties = config.getProperties( true );
1613 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001614 this.helper = ( BaseTracker<T> ) ( ( config.getFactoryPid() == null ) ? managedServiceTracker
1615 : managedServiceFactoryTracker );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001616 }
1617
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001618
1619 protected TargetedPID getTargetedServicePid()
1620 {
1621 final TargetedPID factoryPid = this.config.getFactoryPid();
1622 if ( factoryPid != null )
1623 {
1624 return factoryPid;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001625 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001626 return this.config.getPid();
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001627 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001628
1629
1630 protected boolean provideReplacement( ServiceReference<T> sr )
1631 {
1632 if ( this.config.getFactoryPid() == null )
1633 {
1634 try
1635 {
Felix Meschberger1ff5c532012-07-08 18:23:08 +00001636 final String configPidString = this.helper.getServicePid( sr, this.config.getPid() );
1637 final ConfigurationImpl rc = getTargetedConfiguration( configPidString, sr );
Felix Meschberger273985f2012-07-05 12:28:06 +00001638 if ( rc != null )
1639 {
1640 final TargetedPID configPid;
1641 final Dictionary properties;
1642 final long revision;
Felix Meschbergercd5195f2012-07-05 17:17:45 +00001643 synchronized ( rc )
Felix Meschberger273985f2012-07-05 12:28:06 +00001644 {
Felix Meschbergercd5195f2012-07-05 17:17:45 +00001645 configPid = rc.getPid();
1646 properties = rc.getProperties( true );
1647 revision = rc.getRevision();
Felix Meschberger273985f2012-07-05 12:28:06 +00001648 }
1649
Felix Meschbergercd5195f2012-07-05 17:17:45 +00001650 helper.provideConfiguration( sr, configPid, null, properties, -revision );
Felix Meschberger273985f2012-07-05 12:28:06 +00001651
1652 return true;
1653 }
1654 }
1655 catch ( IOException ioe )
1656 {
1657 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1658 { this.config.getPid(), ioe } );
1659 }
1660 catch ( Exception e )
1661 {
1662 log( LogService.LOG_ERROR, "Unexpected problem providing configuration {0} to service {1}",
1663 new Object[]
1664 { this.config.getPid(), ConfigurationManager.toString( sr ), e } );
1665 }
1666 }
1667
1668 // factory or no replacement available
1669 return false;
1670 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001671 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001672
1673 /**
1674 * The <code>UpdateConfiguration</code> is used to update
1675 * <code>ManagedService[Factory]</code> services with the configuration
1676 * they are subscribed to. This may cause the configuration to be
1677 * supplied to multiple services.
1678 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001679 private class UpdateConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001680 {
1681
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001682 UpdateConfiguration( final ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001683 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001684 super( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001685 }
1686
1687
1688 public void run()
1689 {
Felix Meschberger61207232011-11-17 10:06:45 +00001690 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1691 { config.getPid(), new Long( revision ) } );
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001692
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001693 final List<ServiceReference<?>> srList = this.helper.getServices( getTargetedServicePid() );
1694 if ( !srList.isEmpty() )
Felix Meschberger41cce522009-08-19 05:54:40 +00001695 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001696 // optionally bind dynamically to the first service
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001697 config.tryBindLocation( srList.get( 0 ).getBundle().getLocation() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001698
1699 final String configBundleLocation = config.getBundleLocation();
1700
1701 // provide configuration to all services from the
1702 // correct bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001703 for (ServiceReference<?> ref : srList)
Felix Meschberger41cce522009-08-19 05:54:40 +00001704 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001705 final Bundle refBundle = ref.getBundle();
1706 if ( refBundle == null )
Felix Meschberger41cce522009-08-19 05:54:40 +00001707 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001708 log( LogService.LOG_DEBUG,
1709 "Service {0} seems to be unregistered concurrently (not providing configuration)",
1710 new Object[]
1711 { ConfigurationManager.toString( ref ) } );
1712 }
1713 else if ( canReceive( refBundle, configBundleLocation ) )
1714 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001715 helper.provideConfiguration( ref, this.config.getPid(), this.config.getFactoryPid(),
1716 this.properties, this.revision );
Felix Meschberger2444da62011-11-17 11:17:50 +00001717 }
1718 else
1719 {
1720 // CM 1.4 / 104.13.2.2
Felix Meschberger4f269292011-10-21 13:52:31 +00001721 log( LogService.LOG_ERROR,
1722 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1723 new Object[]
1724 { config.getPid(), ConfigurationManager.toString( ref ), configBundleLocation } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001725 }
1726
Felix Meschberger41cce522009-08-19 05:54:40 +00001727 }
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001728 }
Felix Meschberger137ee722011-11-16 09:51:59 +00001729 else if ( isLogEnabled( LogService.LOG_DEBUG ) )
1730 {
Felix Meschberger1ee888d2011-11-16 12:42:57 +00001731 log( LogService.LOG_DEBUG, "No ManagedService[Factory] registered for updates to configuration {0}",
Felix Meschberger137ee722011-11-16 09:51:59 +00001732 new Object[]
1733 { config.getPid() } );
1734 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001735 }
1736
1737
Felix Meschberger432e3872008-03-07 14:58:57 +00001738 public String toString()
1739 {
1740 return "Update: pid=" + config.getPid();
1741 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001742 }
1743
Felix Meschberger007c50e2011-10-20 12:39:38 +00001744
1745 /**
1746 * The <code>DeleteConfiguration</code> class is used to inform
1747 * <code>ManagedService[Factory]</code> services of a configuration
1748 * being deleted.
1749 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001750 private class DeleteConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001751 {
Felix Meschberger66423332007-08-22 08:46:34 +00001752
Felix Meschbergerc12db8c2009-08-19 06:43:59 +00001753 private final String configLocation;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001754
1755
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001756 DeleteConfiguration( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001757 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001758 /*
1759 * NOTE: We keep the configuration because it might be cleared just
1760 * after calling this method. The pid and factoryPid fields are
1761 * final and cannot be reset.
1762 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001763 super(config);
Felix Meschberger007c50e2011-10-20 12:39:38 +00001764 this.configLocation = config.getBundleLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001765 }
1766
1767
1768 public void run()
1769 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001770 List<ServiceReference<?>> srList = this.helper.getServices( getTargetedServicePid() );
1771 if ( !srList.isEmpty() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001772 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001773 for (ServiceReference<?> sr : srList)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001774 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001775 final Bundle srBundle = sr.getBundle();
1776 if ( srBundle == null )
1777 {
1778 log( LogService.LOG_DEBUG,
1779 "Service {0} seems to be unregistered concurrently (not removing configuration)",
1780 new Object[]
1781 { ConfigurationManager.toString( sr ) } );
1782 }
1783 else if ( canReceive( srBundle, configLocation ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001784 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001785 // revoke configuration unless a replacement
1786 // configuration can be provided
1787 if ( !this.provideReplacement( sr ) )
1788 {
1789 this.helper.removeConfiguration( sr, this.config.getPid(), this.config.getFactoryPid() );
1790 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001791 }
Felix Meschberger2444da62011-11-17 11:17:50 +00001792 else
1793 {
1794 // CM 1.4 / 104.13.2.2
1795 log( LogService.LOG_ERROR,
1796 "Cannot remove configuration {0} for {1}: No visibility to configuration bound to {2}",
1797 new Object[]
1798 { config.getPid(), ConfigurationManager.toString( sr ), configLocation } );
1799 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001800 }
1801 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001802
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001803 final TargetedPID factoryPid = config.getFactoryPid();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001804 if ( factoryPid != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001805 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001806 // remove the pid from the factory
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001807 final String pid = config.getPidString();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001808 try
1809 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001810 Factory factory = getOrCreateFactory( factoryPid.toString() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001811 factory.removePID( pid );
1812 factory.store();
1813 }
1814 catch ( IOException ioe )
1815 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001816 log( LogService.LOG_ERROR, "Failed removing {0} from the factory {1}", new Object[]
1817 { pid, factoryPid, ioe } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001818 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001819 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001820 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001821
Felix Meschberger432e3872008-03-07 14:58:57 +00001822 public String toString()
1823 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001824 return "Delete: pid=" + config.getPid();
Felix Meschberger432e3872008-03-07 14:58:57 +00001825 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001826 }
1827
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001828 private class LocationChanged extends ConfigurationProvider
Felix Meschberger007c50e2011-10-20 12:39:38 +00001829 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001830 private final String oldLocation;
1831
1832
1833 LocationChanged( ConfigurationImpl config, String oldLocation )
1834 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001835 super( config );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001836 this.oldLocation = oldLocation;
1837 }
1838
1839
1840 public void run()
1841 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001842 List<ServiceReference<?>> srList = helper.getServices( getTargetedServicePid() );
1843 if ( !srList.isEmpty() )
Felix Meschberger007c50e2011-10-20 12:39:38 +00001844 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001845 for (final ServiceReference<?> sr : srList)
Felix Meschberger007c50e2011-10-20 12:39:38 +00001846 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001847 final Bundle srBundle = sr.getBundle();
1848 if ( srBundle == null )
1849 {
1850 log( LogService.LOG_DEBUG,
1851 "Service {0} seems to be unregistered concurrently (not processing)", new Object[]
1852 { ConfigurationManager.toString( sr ) } );
1853 continue;
1854 }
1855
1856 final boolean wasVisible = canReceive( srBundle, oldLocation );
1857 final boolean isVisible = canReceive( srBundle, config.getBundleLocation() );
1858
1859 // make sure the config is dynamically bound to the first
1860 // service if the config has been unbound causing this update
1861 if ( isVisible )
1862 {
1863 config.tryBindLocation( srBundle.getLocation() );
1864 }
1865
Felix Meschberger007c50e2011-10-20 12:39:38 +00001866 if ( wasVisible && !isVisible )
1867 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001868 // revoke configuration unless a replacement
1869 // configuration can be provided
1870 if ( !this.provideReplacement( sr ) )
1871 {
1872 helper.removeConfiguration( sr, this.config.getPid(), this.config.getFactoryPid() );
1873 log( LogService.LOG_DEBUG, "Configuration {0} revoked from {1} (no more visibility)",
1874 new Object[]
1875 { config.getPid(), ConfigurationManager.toString( sr ) } );
1876 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001877 }
1878 else if ( !wasVisible && isVisible )
1879 {
1880 // call updated method
Felix Meschberger273985f2012-07-05 12:28:06 +00001881 helper.provideConfiguration( sr, this.config.getPid(), this.config.getFactoryPid(),
1882 this.properties, this.revision );
Felix Meschberger4f269292011-10-21 13:52:31 +00001883 log( LogService.LOG_DEBUG, "Configuration {0} provided to {1} (new visibility)", new Object[]
1884 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger35658d52011-10-20 21:43:58 +00001885 }
Felix Meschberger4f269292011-10-21 13:52:31 +00001886 else
Felix Meschberger35658d52011-10-20 21:43:58 +00001887 {
1888 // same visibility as before
Felix Meschberger4f269292011-10-21 13:52:31 +00001889 log( LogService.LOG_DEBUG, "Unmodified visibility to configuration {0} for {1}", new Object[]
1890 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001891 }
1892 }
1893 }
1894 }
1895
1896
1897 public String toString()
1898 {
1899 return "Location Changed (pid=" + config.getPid() + "): " + oldLocation + " ==> "
1900 + config.getBundleLocation();
1901 }
1902 }
1903
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001904 private class FireConfigurationEvent implements Runnable
1905 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001906 private final int type;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001907
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001908 private final String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001909
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001910 private final String factoryPid;
1911
1912 private final ServiceReference[] listenerReferences;
1913
1914 private final ConfigurationListener[] listeners;
1915
1916 private final Bundle[] listenerProvider;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001917
Felix Meschberger0770cad2012-06-11 12:36:52 +00001918 private ConfigurationEvent event;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001919
Felix Meschbergere94b1572012-07-14 11:59:29 +00001920 private FireConfigurationEvent( final ServiceTracker listenerTracker, final int type, final String pid, final String factoryPid)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001921 {
1922 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001923 this.pid = pid;
1924 this.factoryPid = factoryPid;
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001925
Felix Meschbergere94b1572012-07-14 11:59:29 +00001926 final ServiceReference[] srs = listenerTracker.getServiceReferences();
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001927 if ( srs == null || srs.length == 0 )
1928 {
1929 this.listenerReferences = null;
1930 this.listeners = null;
1931 this.listenerProvider = null;
1932 }
1933 else
1934 {
1935 this.listenerReferences = srs;
1936 this.listeners = new ConfigurationListener[srs.length];
1937 this.listenerProvider = new Bundle[srs.length];
1938 for ( int i = 0; i < srs.length; i++ )
1939 {
Felix Meschbergere94b1572012-07-14 11:59:29 +00001940 this.listeners[i] = ( ConfigurationListener ) listenerTracker.getService( srs[i] );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001941 this.listenerProvider[i] = srs[i].getBundle();
1942 }
1943 }
1944 }
1945
1946
1947 boolean hasConfigurationEventListeners()
1948 {
1949 return this.listenerReferences != null;
1950 }
1951
1952
1953 String getTypeName()
1954 {
1955 switch ( type )
1956 {
1957 case ConfigurationEvent.CM_DELETED:
1958 return "CM_DELETED";
1959 case ConfigurationEvent.CM_UPDATED:
1960 return "CM_UPDATED";
Felix Meschberger007c50e2011-10-20 12:39:38 +00001961 case ConfigurationEvent.CM_LOCATION_CHANGED:
1962 return "CM_LOCATION_CHANGED";
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001963 default:
1964 return "<UNKNOWN(" + type + ")>";
1965 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001966 }
1967
1968
1969 public void run()
1970 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001971 for ( int i = 0; i < listeners.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001972 {
Felix Meschberger0770cad2012-06-11 12:36:52 +00001973 sendEvent( i );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001974 }
1975 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001976
Felix Meschberger0770cad2012-06-11 12:36:52 +00001977
Felix Meschberger432e3872008-03-07 14:58:57 +00001978 public String toString()
1979 {
1980 return "Fire ConfigurationEvent: pid=" + pid;
1981 }
Felix Meschberger0770cad2012-06-11 12:36:52 +00001982
1983
1984 private ConfigurationEvent getConfigurationEvent()
1985 {
1986 if ( event == null )
1987 {
1988 this.event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
1989 }
1990 return event;
1991 }
1992
1993
1994 private void sendEvent( final int serviceIndex )
1995 {
1996 if ( listenerProvider[serviceIndex].getState() == Bundle.ACTIVE && this.listeners[serviceIndex] != null )
1997 {
1998 log( LogService.LOG_DEBUG, "Sending {0} event for {1} to {2}", new Object[]
1999 { getTypeName(), pid, ConfigurationManager.toString( listenerReferences[serviceIndex] ) } );
2000
2001 try
2002 {
2003 listeners[serviceIndex].configurationEvent( getConfigurationEvent() );
2004 }
2005 catch ( Throwable t )
2006 {
2007 log( LogService.LOG_ERROR, "Unexpected problem delivering configuration event to {0}", new Object[]
2008 { ConfigurationManager.toString( listenerReferences[serviceIndex] ), t } );
2009 }
2010 finally
2011 {
2012 this.listeners[serviceIndex] = null;
2013 }
2014 }
2015 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002016 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002017}
Felix Meschberger273985f2012-07-05 12:28:06 +00002018