blob: 9eccab3c084ed33cea20ac1e730e7d7ac1c3814a [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
138 // service tracker for managed services
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000139 private ManagedServiceTracker managedServiceTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000140
141 // service tracker for managed service factories
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000142 private ManagedServiceFactoryTracker managedServiceFactoryTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000143
144 // PersistenceManager services
145 private ServiceTracker persistenceManagerTracker;
146
147 // the thread used to schedule tasks required to run asynchronously
148 private UpdateThread updateThread;
149
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000150 // the thread used to schedule events to be dispatched asynchronously
151 private UpdateThread eventThread;
152
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000153 /**
154 * The actual list of {@link PersistenceManager persistence managers} to use
155 * when looking for configuration data. This list is built from the
156 * {@link #persistenceManagerMap}, which is ordered according to the
157 * {@link RankingComparator}.
158 */
159 private PersistenceManager[] persistenceManagers;
160
161 // the persistenceManagerTracker.getTrackingCount when the
162 // persistenceManagers were last got
163 private int pmtCount;
164
165 // the cache of Factory instances mapped by their factory PID
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000166 private final HashMap<String, Factory> factories = new HashMap<String, Factory>();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000167
168 // the cache of Configuration instances mapped by their PID
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000169 // have this always set to prevent NPE on bundle shutdown
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000170 private final HashMap<String, ConfigurationImpl> configurations = new HashMap<String, ConfigurationImpl>();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000171
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000172 /**
173 * The map of dynamic configuration bindings. This maps the
174 * PID of the dynamically bound configuration or factory to its bundle
175 * location.
176 * <p>
177 * On bundle startup this map is loaded from persistence and validated
178 * against the locations of installed bundles: Entries pointing to bundle
179 * locations not currently installed are removed.
180 * <p>
181 * The map is written to persistence on each change.
182 */
183 private DynamicBindings dynamicBindings;
184
Felix Meschberger08282c32009-01-28 07:01:55 +0000185 // the maximum log level when no LogService is available
186 private int logLevel = CM_LOG_LEVEL_DEFAULT;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000187
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000188 // flag indicating whether BundleChange events should be consumed (FELIX-979)
189 private volatile boolean handleBundleEvents;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000190
Felix Meschberger623f7142012-01-31 07:13:37 +0000191 // flag indicating whether the manager is considered alive
192 private volatile boolean isActive;
193
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000194 public void start( BundleContext bundleContext )
195 {
196 // track the log service using a ServiceTracker
Felix Meschberger85b355d2007-08-31 07:17:38 +0000197 logTracker = new ServiceTracker( bundleContext, LOG_SERVICE_NAME , null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000198 logTracker.open();
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000199
Felix Meschberger08282c32009-01-28 07:01:55 +0000200 // assign the log level
201 String logLevelProp = bundleContext.getProperty( CM_LOG_LEVEL );
202 if ( logLevelProp == null )
203 {
204 logLevel = CM_LOG_LEVEL_DEFAULT;
205 }
206 else
207 {
208 try
209 {
210 logLevel = Integer.parseInt( logLevelProp );
211 }
212 catch ( NumberFormatException nfe )
213 {
214 logLevel = CM_LOG_LEVEL_DEFAULT;
215 }
216 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000217
218 // set up some fields
219 this.bundleContext = bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000220
221 // configurationlistener support
222 configurationListenerTracker = new ServiceTracker( bundleContext, ConfigurationListener.class.getName(), null );
223 configurationListenerTracker.open();
224
225 // initialize the asynchonous updater thread
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000226 ThreadGroup tg = new ThreadGroup( "Configuration Admin Service" );
227 tg.setDaemon( true );
228 this.updateThread = new UpdateThread( this, tg, "CM Configuration Updater" );
229 this.eventThread = new UpdateThread( this, tg, "CM Event Dispatcher" );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000230
231 // set up the location (might throw IllegalArgumentException)
232 try
233 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000234 FilePersistenceManager fpm = new FilePersistenceManager( bundleContext, bundleContext
235 .getProperty( CM_CONFIG_DIR ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000236 Hashtable props = new Hashtable();
237 props.put( Constants.SERVICE_PID, fpm.getClass().getName() );
238 props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
239 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
240 props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
241 bundleContext.registerService( PersistenceManager.class.getName(), fpm, props );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000242
243 // setup dynamic configuration bindings
244 dynamicBindings = new DynamicBindings( bundleContext, fpm );
245 }
246 catch ( IOException ioe )
247 {
248 log( LogService.LOG_ERROR, "Failure setting up dynamic configuration bindings", ioe );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000249 }
250 catch ( IllegalArgumentException iae )
251 {
252 log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
253 }
254
255 // register as bundle and service listener
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000256 handleBundleEvents = true;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000257 bundleContext.addBundleListener( this );
258
259 // get all persistence managers to begin with
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000260 pmtCount = 1; // make sure to get the persistence managers at least once
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000261 persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
262 persistenceManagerTracker.open();
263
Felix Meschberger623f7142012-01-31 07:13:37 +0000264 // consider alive now (before clients use Configuration Admin
265 // service registered in the next step)
266 isActive = true;
267
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000268 // create and register configuration admin - start after PM tracker ...
269 ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
270 Hashtable props = new Hashtable();
271 props.put( Constants.SERVICE_PID, "org.apache.felix.cm.ConfigurationAdmin" );
272 props.put( Constants.SERVICE_DESCRIPTION, "Configuration Admin Service Specification 1.2 Implementation" );
273 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000274 configurationAdminRegistration = bundleContext.registerService( ConfigurationAdmin.class.getName(), caf, props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000275
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000276 // start handling ManagedService[Factory] services
277 managedServiceTracker = new ManagedServiceTracker(this);
278 managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this);
279
Felix Meschberger4b26df92011-02-01 12:41:45 +0000280 // start processing the event queues only after registering the service
281 // see FELIX-2813 for details
282 this.updateThread.start();
283 this.eventThread.start();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000284 }
285
286
287 public void stop( BundleContext bundleContext )
288 {
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000289
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000290 // stop handling bundle events immediately
291 handleBundleEvents = false;
292
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000293 // stop handling ManagedService[Factory] services
294 managedServiceFactoryTracker.close();
295 managedServiceTracker.close();
296
Felix Meschberger4b26df92011-02-01 12:41:45 +0000297 // stop queue processing before unregistering the service
298 // see FELIX-2813 for details
299 if ( updateThread != null )
300 {
301 updateThread.terminate();
302 }
303 if ( eventThread != null )
304 {
305 eventThread.terminate();
306 }
307
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000308 // immediately unregister the Configuration Admin before cleaning up
Felix Meschberger10568352009-01-15 08:57:11 +0000309 // clearing the field before actually unregistering the service
310 // prevents IllegalStateException in getServiceReference() if
311 // the field is not null but the service already unregistered
312 if (configurationAdminRegistration != null) {
313 ServiceRegistration reg = configurationAdminRegistration;
314 configurationAdminRegistration = null;
315 reg.unregister();
316 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000317
Felix Meschberger623f7142012-01-31 07:13:37 +0000318 // consider inactive after unregistering such that during
319 // unregistration the manager is still alive and can react
320 isActive = false;
321
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000322 // don't care for PersistenceManagers any more
323 persistenceManagerTracker.close();
324
325 // stop listening for events
326 bundleContext.removeBundleListener( this );
327
328 if ( configurationListenerTracker != null )
329 {
330 configurationListenerTracker.close();
331 }
332
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000333 if ( logTracker != null )
334 {
335 logTracker.close();
336 }
337
Felix Meschberger6a698df2009-08-16 18:38:46 +0000338 // just ensure the configuration cache is empty
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000339 synchronized ( configurations )
340 {
341 configurations.clear();
342 }
343
Felix Meschberger6a698df2009-08-16 18:38:46 +0000344 // just ensure the factory cache is empty
345 synchronized ( factories )
346 {
347 factories.clear();
348 }
349
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000350 this.bundleContext = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000351 }
352
353
Felix Meschberger623f7142012-01-31 07:13:37 +0000354 /**
355 * Returns <code>true</code> if this manager is considered active.
356 */
357 boolean isActive()
358 {
359 return isActive;
360 }
361
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000362 public BundleContext getBundleContext()
363 {
364 return bundleContext;
365 }
Felix Meschberger623f7142012-01-31 07:13:37 +0000366
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000367 // ---------- Configuration caching support --------------------------------
368
369 ConfigurationImpl getCachedConfiguration( String pid )
370 {
371 synchronized ( configurations )
372 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000373 return configurations.get( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000374 }
375 }
376
377
Felix Meschberger6a698df2009-08-16 18:38:46 +0000378 ConfigurationImpl[] getCachedConfigurations()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000379 {
380 synchronized ( configurations )
381 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000382 return configurations.values().toArray(
Felix Meschberger6a698df2009-08-16 18:38:46 +0000383 new ConfigurationImpl[configurations.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000384 }
385 }
386
387
Felix Meschberger2941ef92007-08-20 13:15:16 +0000388 ConfigurationImpl cacheConfiguration( ConfigurationImpl configuration )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000389 {
390 synchronized ( configurations )
391 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000392 final String pid = configuration.getPidString();
393 final Object existing = configurations.get( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000394 if ( existing != null )
395 {
396 return ( ConfigurationImpl ) existing;
397 }
398
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000399 configurations.put( pid, configuration );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000400 return configuration;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000401 }
402 }
403
404
405 void removeConfiguration( ConfigurationImpl configuration )
406 {
407 synchronized ( configurations )
408 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000409 configurations.remove( configuration.getPidString() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000410 }
411 }
412
413
Felix Meschberger6a698df2009-08-16 18:38:46 +0000414 Factory getCachedFactory( String factoryPid )
415 {
416 synchronized ( factories )
417 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000418 return factories.get( factoryPid );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000419 }
420 }
421
422
423 Factory[] getCachedFactories()
424 {
425 synchronized ( factories )
426 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000427 return factories.values().toArray( new Factory[factories.size()] );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000428 }
429 }
430
431
432 void cacheFactory( Factory factory )
433 {
434 synchronized ( factories )
435 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000436 factories.put( factory.getFactoryPidString(), factory );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000437 }
438 }
439
440
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000441 // ---------- ConfigurationAdminImpl support
Felix Meschberger6a698df2009-08-16 18:38:46 +0000442
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000443 void setDynamicBundleLocation( final String pid, final String location )
444 {
445 if ( dynamicBindings != null )
446 {
447 try
448 {
449 dynamicBindings.putLocation( pid, location );
450 }
451 catch ( IOException ioe )
452 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000453 log( LogService.LOG_ERROR, "Failed storing dynamic configuration binding for {0} to {1}", new Object[]
454 { pid, location, ioe } );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000455 }
456 }
457 }
458
459
460 String getDynamicBundleLocation( final String pid )
461 {
462 if ( dynamicBindings != null )
463 {
464 return dynamicBindings.getLocation( pid );
465 }
466
467 return null;
468 }
469
470
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000471 ConfigurationImpl createFactoryConfiguration( String factoryPid, String location ) throws IOException
472 {
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000473 return cacheConfiguration( createConfiguration( createPid( factoryPid ), factoryPid, location ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000474 }
475
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000476 /**
477 * Returns a targeted configuration for the given service PID and
478 * the reference target service.
Felix Meschberger273985f2012-07-05 12:28:06 +0000479 * <p>
480 * A configuration returned has already been checked for visibility
481 * by the bundle registering the referenced service. Additionally,
482 * the configuration is also dynamically bound if needed.
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000483 *
484 * @param rawPid The raw service PID to get targeted configuration for.
485 * @param target The target <code>ServiceReference</code> to get
486 * configuration for.
487 * @return The best matching targeted configuration or <code>null</code>
488 * if there is no configuration at all.
489 * @throwss IOException if an error occurrs reading configurations
490 * from persistence.
491 */
492 ConfigurationImpl getTargetedConfiguration( final String rawPid, final ServiceReference target ) throws IOException
493 {
494 final Bundle serviceBundle = target.getBundle();
495 if ( serviceBundle != null )
496 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000497 // list of targeted PIDs to check
498 // (StringBuffer for pre-1.5 API compatibility)
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000499 final StringBuffer targetedPid = new StringBuffer( rawPid );
500 int i = 3;
501 String[] names = new String[4];
502 names[i--] = targetedPid.toString();
503 targetedPid.append( '|' ).append( serviceBundle.getSymbolicName() );
504 names[i--] = targetedPid.toString();
505 targetedPid.append( '|' ).append( TargetedPID.getBundleVersion( serviceBundle ) );
506 names[i--] = targetedPid.toString();
507 targetedPid.append( '|' ).append( serviceBundle.getLocation() );
508 names[i--] = targetedPid.toString();
509
510 for ( String candidate : names )
511 {
512 ConfigurationImpl config = getConfiguration( candidate );
Felix Meschbergercd5195f2012-07-05 17:17:45 +0000513 if ( config != null && !config.isDeleted() )
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000514 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000515 // check visibility to use and dynamically bind
516 if ( canReceive( serviceBundle, config.getBundleLocation() ) )
517 {
518 config.tryBindLocation( serviceBundle.getLocation() );
519 return config;
520 }
521
522 // CM 1.4 / 104.13.2.2 / 104.5.3
523 // act as if there is no configuration
524 log(
525 LogService.LOG_DEBUG,
526 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}; calling with null",
527 new Object[]
528 { config.getPid(), toString( target ), config.getBundleLocation() } );
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000529 }
530 }
531 }
Felix Meschberger273985f2012-07-05 12:28:06 +0000532 else
533 {
534 log( LogService.LOG_INFO,
535 "Service for PID {0} seems to already have been unregistered, not updating with configuration",
536 new Object[]
537 { rawPid } );
538 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000539
540 // service already unregistered, nothing to do really
541 return null;
542 }
543
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000544
Felix Meschbergerad949872011-11-16 10:34:54 +0000545 /**
546 * Returns the {@link ConfigurationImpl} with the given PID if
547 * available in the internal cache or from any persistence manager.
548 * Otherwise <code>null</code> is returned.
549 *
550 * @param pid The PID for which to return the configuration
551 * @return The configuration or <code>null</code> if non exists
552 * @throws IOException If an error occurrs reading from a persistence
553 * manager.
554 */
555 ConfigurationImpl getConfiguration( String pid ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000556 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000557 ConfigurationImpl config = getCachedConfiguration( pid );
558 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000559 {
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000560 log( LogService.LOG_DEBUG, "Found cached configuration {0} bound to {1}", new Object[]
561 { pid, config.getBundleLocation() } );
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000562
563 config.ensureFactoryConfigPersisted();
564
Felix Meschberger2941ef92007-08-20 13:15:16 +0000565 return config;
566 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000567
Felix Meschberger2941ef92007-08-20 13:15:16 +0000568 PersistenceManager[] pmList = getPersistenceManagers();
569 for ( int i = 0; i < pmList.length; i++ )
570 {
571 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000572 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000573 Dictionary props = pmList[i].load( pid );
574 config = new ConfigurationImpl( this, pmList[i], props );
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000575 log( LogService.LOG_DEBUG, "Found existing configuration {0} bound to {1}", new Object[]
576 { pid, config.getBundleLocation() } );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000577 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000578 }
579 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000580
Felix Meschberger2941ef92007-08-20 13:15:16 +0000581 // neither the cache nor any persistence manager has configuration
582 return null;
583 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000584
585
Felix Meschbergerad949872011-11-16 10:34:54 +0000586 /**
587 * Creates a regular (non-factory) configuration for the given PID
588 * setting the bundle location accordingly.
589 * <p>
590 * This method assumes the configuration to not exist yet and will
591 * create it without further checking.
592 *
593 * @param pid The PID of the new configuration
594 * @param bundleLocation The location to set on the new configuration.
595 * This may be <code>null</code> to not bind the configuration
596 * yet.
597 * @return The new configuration persisted in the first persistence
598 * manager.
599 * @throws IOException If an error occurrs writing the configuration
600 * to the persistence.
601 */
602 ConfigurationImpl createConfiguration( String pid, String bundleLocation ) throws IOException
Felix Meschberger2941ef92007-08-20 13:15:16 +0000603 {
604 // check for existing (cached or persistent) configuration
Felix Meschbergerad949872011-11-16 10:34:54 +0000605 ConfigurationImpl config = getConfiguration( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000606 if ( config != null )
607 {
608 return config;
609 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000610
Felix Meschberger2941ef92007-08-20 13:15:16 +0000611 // else create new configuration also setting the bundle location
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000612 // and cache the new configuration
613 config = createConfiguration( pid, null, bundleLocation );
614 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000615 }
616
617
618 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
619 throws IOException, InvalidSyntaxException
620 {
621 Filter filter = null;
622 if ( filterString != null )
623 {
624 filter = bundleContext.createFilter( filterString );
625 }
626
Felix Meschberger4f269292011-10-21 13:52:31 +0000627 log( LogService.LOG_DEBUG, "Listing configurations matching {0}", new Object[]
628 { filterString } );
629
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000630 List configList = new ArrayList();
631
632 PersistenceManager[] pmList = getPersistenceManagers();
633 for ( int i = 0; i < pmList.length; i++ )
634 {
635 Enumeration configs = pmList[i].getDictionaries();
636 while ( configs.hasMoreElements() )
637 {
638 Dictionary config = ( Dictionary ) configs.nextElement();
639
640 // ignore non-Configuration dictionaries
Felix Meschberger86a0d172007-07-04 07:15:01 +0000641 String pid = ( String ) config.get( Constants.SERVICE_PID );
642 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000643 {
644 continue;
645 }
646
Felix Meschberger007c50e2011-10-20 12:39:38 +0000647 // CM 1.4 / 104.13.2.3 Permission required
648 if ( !configurationAdmin.hasPermission( ( String ) config
649 .get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000650 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000651 log(
652 LogService.LOG_DEBUG,
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000653 "Omitting configuration {0}: No permission for bundle {1} on configuration bound to {2}",
Felix Meschberger4f269292011-10-21 13:52:31 +0000654 new Object[]
655 { config.get( Constants.SERVICE_PID ), configurationAdmin.getBundle().getLocation(),
656 config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000657 continue;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000658 }
659
660 // check filter
661 if ( filter == null || filter.match( config ) )
662 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000663 // ensure the service.pid and returned a cached config if available
664 ConfigurationImpl cfg = getCachedConfiguration( pid );
665 if ( cfg == null )
666 {
667 cfg = new ConfigurationImpl( this, pmList[i], config );
668 }
669
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000670 // FELIX-611: Ignore configuration objects without props
671 if ( !cfg.isNew() )
672 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000673 log( LogService.LOG_DEBUG, "Adding configuration {0}", new Object[]
674 { config.get( Constants.SERVICE_PID ) } );
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000675 configList.add( cfg );
676 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000677 else
678 {
679 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Is new", new Object[]
680 { config.get( Constants.SERVICE_PID ) } );
681 }
682 } else {
683 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Does not match filter", new Object[]
684 { config.get( Constants.SERVICE_PID ) } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000685 }
686 }
687 }
688
Felix Meschberger8faceff2007-07-04 07:19:48 +0000689 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000690 .size()] );
691 }
692
693
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000694 void deleted( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000695 {
696 // remove the configuration from the cache
697 removeConfiguration( config );
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000698 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000699 updateThread.schedule( new DeleteConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000700 log( LogService.LOG_DEBUG, "DeleteConfiguration({0}) scheduled", new Object[]
701 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000702 }
703
704
Felix Meschbergerce67d732009-08-20 06:26:35 +0000705 void updated( ConfigurationImpl config, boolean fireEvent )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000706 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000707 if ( fireEvent )
708 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000709 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000710 }
711 updateThread.schedule( new UpdateConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000712 log( LogService.LOG_DEBUG, "UpdateConfiguration({0}) scheduled", new Object[]
713 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000714 }
715
716
Felix Meschberger007c50e2011-10-20 12:39:38 +0000717 void locationChanged( ConfigurationImpl config, String oldLocation )
718 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000719 fireConfigurationEvent( ConfigurationEvent.CM_LOCATION_CHANGED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger35658d52011-10-20 21:43:58 +0000720 if ( oldLocation != null && !config.isNew() )
Felix Meschberger007c50e2011-10-20 12:39:38 +0000721 {
722 updateThread.schedule( new LocationChanged( config, oldLocation ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000723 log( LogService.LOG_DEBUG, "LocationChanged({0}, {1}=>{2}) scheduled", new Object[]
724 { config.getPid(), oldLocation, config.getBundleLocation() } );
Felix Meschberger35658d52011-10-20 21:43:58 +0000725 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000726 else
Felix Meschberger35658d52011-10-20 21:43:58 +0000727 {
728 log( LogService.LOG_DEBUG,
Felix Meschberger4f269292011-10-21 13:52:31 +0000729 "LocationChanged not scheduled for {0} (old location is null or configuration is new)", new Object[]
730 { config.getPid() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000731 }
732 }
733
734
Felix Meschberger66423332007-08-22 08:46:34 +0000735 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000736 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000737 FireConfigurationEvent event = new FireConfigurationEvent( type, pid, factoryPid );
Felix Meschberger0770cad2012-06-11 12:36:52 +0000738 event.fireSynchronousEvents();
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000739 if ( event.hasConfigurationEventListeners() )
740 {
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000741 eventThread.schedule( event );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000742 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000743 else
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000744 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000745 log( LogService.LOG_DEBUG, "No ConfigurationListeners to send {0} event to.", new Object[]
746 { event.getTypeName() } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000747 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000748 }
749
750
751 // ---------- BundleListener -----------------------------------------------
752
753 public void bundleChanged( BundleEvent event )
754 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000755 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000756 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000757 final String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000758
Felix Meschberger6a698df2009-08-16 18:38:46 +0000759 // we only reset dynamic bindings, which are only present in
760 // cached configurations, hence only consider cached configs here
761 final ConfigurationImpl[] configs = getCachedConfigurations();
762 for ( int i = 0; i < configs.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000763 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000764 final ConfigurationImpl cfg = configs[i];
Felix Meschberger41cce522009-08-19 05:54:40 +0000765 if ( location.equals( cfg.getDynamicBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000766 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000767 cfg.setDynamicBundleLocation( null, true );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000768 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000769 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000770 }
771 }
772
773
774 // ---------- internal -----------------------------------------------------
775
776 private PersistenceManager[] getPersistenceManagers()
777 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000778 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
779 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000780 {
781
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000782 List pmList = new ArrayList();
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000783 PersistenceManager[] pm;
784
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000785 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
786 if ( refs == null || refs.length == 0 )
787 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000788 pm = new PersistenceManager[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000789 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000790 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000791 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000792 // sort the references according to the cmRanking property
Felix Meschberger007c50e2011-10-20 12:39:38 +0000793 if ( refs.length > 1 )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000794 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000795 Arrays.sort( refs, RankingComparator.SRV_RANKING );
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000796 }
797
798 // create the service array from the sorted set of referenecs
Felix Meschberger007c50e2011-10-20 12:39:38 +0000799 for ( int i = 0; i < refs.length; i++ )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000800 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000801 Object service = persistenceManagerTracker.getService( refs[i] );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000802 if ( service != null )
803 {
Felix Meschbergera86cdfc2010-08-25 09:32:36 +0000804 pmList.add( new CachingPersistenceManagerProxy( ( PersistenceManager ) service ) );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000805 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000806 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000807
808 pm = ( PersistenceManager[] ) pmList.toArray( new PersistenceManager[pmList.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000809 }
810
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000811 pmtCount = pm.length;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000812 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000813 }
814
815 return persistenceManagers;
816 }
817
818
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000819 private ServiceReference getServiceReference()
820 {
821 ServiceRegistration reg = configurationAdminRegistration;
Felix Meschberger0770cad2012-06-11 12:36:52 +0000822 if (reg != null) {
823 return reg.getReference();
824 }
825
826 // probably called for firing an event during service registration
827 // since we didn't get the service registration yet we use the
828 // service registry to get our service reference
829 BundleContext context = bundleContext;
830 if ( context != null )
831 {
832 try
833 {
834 ServiceReference[] refs = context.getServiceReferences( ConfigurationAdmin.class.getName(), null );
835 if ( refs != null )
836 {
837 for ( int i = 0; i < refs.length; i++ )
838 {
839 if ( refs[i].getBundle().getBundleId() == context.getBundle().getBundleId() )
840 {
841 return refs[i];
842 }
843 }
844 }
845 }
846 catch ( InvalidSyntaxException e )
847 {
848 // unexpected since there is no filter
849 }
850 }
851
852 // service references
853 return null;
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000854 }
855
856
Felix Meschberger05d89e12011-11-03 23:37:10 +0000857 /**
858 * Configures the ManagedService and returns the service.pid
859 * service property as a String[], which may be <code>null</code> if
860 * the ManagedService does not have such a property.
861 */
Felix Meschberger05d89e12011-11-03 23:37:10 +0000862 /**
863 * Configures the ManagedServiceFactory and returns the service.pid
864 * service property as a String[], which may be <code>null</code> if
865 * the ManagedServiceFactory does not have such a property.
866 */
Felix Meschberger382a19b2012-07-03 09:45:14 +0000867 /**
868 * Schedules the configuration of the referenced service with
869 * configuration for the given PID.
870 *
Felix Meschberger273985f2012-07-05 12:28:06 +0000871 * @param pid The list of service PID of the configurations to be
872 * provided to the referenced service.
Felix Meschberger382a19b2012-07-03 09:45:14 +0000873 * @param sr The <code>ServiceReference</code> to the service
874 * to be configured.
875 * @param factory <code>true</code> If the service is considered to
876 * be a <code>ManagedServiceFactory</code>. Otherwise the service
877 * is considered to be a <code>ManagedService</code>.
878 */
Felix Meschberger273985f2012-07-05 12:28:06 +0000879 public void configure( String[] pid, ServiceReference sr, final boolean factory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000880 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000881 if ( this.isLogEnabled( LogService.LOG_DEBUG ) )
882 {
883 this.log( LogService.LOG_DEBUG, "configure(ManagedService {0})", new Object[]
884 { toString( sr ) } );
885 }
886
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000887 Runnable r;
888 if ( factory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000889 {
Felix Meschberger382a19b2012-07-03 09:45:14 +0000890 r = new ManagedServiceFactoryUpdate( pid, sr );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000891 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000892 else
893 {
Felix Meschberger382a19b2012-07-03 09:45:14 +0000894 r = new ManagedServiceUpdate( pid, sr );
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000895 }
896 updateThread.schedule( r );
897 log( LogService.LOG_DEBUG, "[{0}] scheduled", new Object[]
898 { r } );
Felix Meschberger851c6412009-08-16 18:43:26 +0000899 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000900
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000901
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000902 /**
903 * Factory method to create a new configuration object. The configuration
904 * object returned is not stored in configuration cache and only persisted
905 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000906 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000907 * @param pid
908 * The PID of the new configuration object. Must not be
909 * <code>null</code>.
910 * @param factoryPid
911 * The factory PID of the new configuration. Not
Felix Meschberger6a698df2009-08-16 18:38:46 +0000912 * <code>null</code> if the new configuration object belongs to a
913 * factory. The configuration object will not be persisted if
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000914 * this parameter is not <code>null</code>.
915 * @param bundleLocation
916 * The bundle location of the bundle to which the configuration
Felix Meschberger6a698df2009-08-16 18:38:46 +0000917 * belongs or <code>null</code> if the configuration is not bound
918 * yet.
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000919 * @return The new configuration object
920 * @throws IOException
921 * May be thrown if an error occurrs persisting the new
922 * configuration object.
923 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000924 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000925 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000926 log( LogService.LOG_DEBUG, "createConfiguration({0}, {1}, {2})", new Object[]
927 { pid, factoryPid, bundleLocation } );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000928 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000929 }
930
931
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000932 /**
933 * Returns a list of {@link Factory} instances according to the
934 * Configuration Admin 1.5 specification for targeted PIDs (Section
935 * 104.3.2)
936 *
937 * @param rawFactoryPid The raw factory PID without any targetting.
938 * @param target The <code>ServiceReference</code> of the service to
939 * be supplied with targeted configuration.
940 * @return A list of {@link Factory} instances as listed above. This
941 * list will always at least include an instance for the
942 * <code>rawFactoryPid</code>. Other instances are only included
943 * if existing.
944 * @throws IOException If an error occurrs reading any of the
945 * {@link Factory} instances from persistence
946 */
947 List<Factory> getTargetedFactories( final String rawFactoryPid, final ServiceReference target ) throws IOException
948 {
949 LinkedList<Factory> factories = new LinkedList<Factory>();
950
951 final Bundle serviceBundle = target.getBundle();
952 if ( serviceBundle != null )
953 {
954 // for pre-1.5 API compatibility
955 final StringBuffer targetedPid = new StringBuffer( rawFactoryPid );
956 factories.add( getOrCreateFactory( targetedPid.toString() ) );
957
958 targetedPid.append( '|' ).append( serviceBundle.getSymbolicName() );
959 Factory f = getFactory( targetedPid.toString() );
960 if ( f != null )
961 {
962 factories.add( 0, f );
963 }
964
965 targetedPid.append( '|' ).append( TargetedPID.getBundleVersion( serviceBundle ) );
966 f = getFactory( targetedPid.toString() );
967 if ( f != null )
968 {
969 factories.add( 0, f );
970 }
971
972 targetedPid.append( '|' ).append( serviceBundle.getLocation() );
973 f = getFactory( targetedPid.toString() );
974 if ( f != null )
975 {
976 factories.add( 0, f );
977 }
978 }
979
980 return factories;
981 }
982
983
984 /**
985 * Gets the factory with the exact identifier from the cached or from
986 * the persistence managers. If no factory exists already one is
987 * created and cached.
988 *
989 * @param factoryPid The PID of the {@link Factory} to return
990 * @return The existing or newly created {@link Factory}
991 * @throws IOException If an error occurrs reading the factory from
992 * a {@link PersistenceManager}
993 */
994 Factory getOrCreateFactory( String factoryPid ) throws IOException
995 {
996 Factory factory = getFactory( factoryPid );
997 if ( factory != null )
998 {
999 return factory;
1000 }
1001
1002 return createFactory( factoryPid );
1003 }
1004
1005
1006 /**
1007 * Gets the factory with the exact identifier from the cached or from
1008 * the persistence managers. If no factory exists <code>null</code>
1009 * is returned.
1010 *
1011 * @param factoryPid The PID of the {@link Factory} to return
1012 * @return The existing {@link Factory} or <code>null</code>
1013 * @throws IOException If an error occurrs reading the factory from
1014 * a {@link PersistenceManager}
1015 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001016 Factory getFactory( String factoryPid ) throws IOException
1017 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001018 // check for cached factory
Felix Meschbergerf4631322008-03-10 12:32:35 +00001019 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001020 if ( factory != null )
1021 {
1022 return factory;
1023 }
1024
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001025 // try to load factory from persistence
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001026 PersistenceManager[] pmList = getPersistenceManagers();
1027 for ( int i = 0; i < pmList.length; i++ )
1028 {
1029 if ( Factory.exists( pmList[i], factoryPid ) )
1030 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +00001031 factory = Factory.load( this, pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001032 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001033 return factory;
1034 }
1035 }
1036
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001037 // no existing factory
1038 return null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001039 }
1040
1041
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001042 /**
1043 * Creates a new factory with the given <code>factoryPid</code>.
1044 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001045 Factory createFactory( String factoryPid )
1046 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +00001047 Factory factory = new Factory( this, getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001048 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001049 return factory;
1050 }
1051
1052
Felix Meschberger2941ef92007-08-20 13:15:16 +00001053 /**
1054 * Calls the registered configuration plugins on the given configuration
Felix Meschberger273985f2012-07-05 12:28:06 +00001055 * properties from the given configuration object.
1056 * <p>
1057 * The plugins to be called are selected as <code>ConfigurationPlugin</code>
1058 * services registered with a <code>cm.target</code> property set to
1059 * <code>*</code> or the factory PID of the configuration (for factory
1060 * configurations) or the PID of the configuration (for non-factory
1061 * configurations).
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001062 *
Felix Meschberger41cce522009-08-19 05:54:40 +00001063 * @param props The configuraiton properties run through the registered
Felix Meschberger273985f2012-07-05 12:28:06 +00001064 * ConfigurationPlugin services. This must not be
1065 * <code>null</code>.
Felix Meschberger2941ef92007-08-20 13:15:16 +00001066 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001067 * is to be updated with configuration
Felix Meschberger273985f2012-07-05 12:28:06 +00001068 * @param configPid The PID of the configuration object whose properties
1069 * are to be augmented
1070 * @param factoryPid the factory PID of the configuration object whose
1071 * properties are to be augmented. This is non-<code>null</code>
1072 * only for a factory configuration.
Felix Meschberger2941ef92007-08-20 13:15:16 +00001073 */
Felix Meschberger273985f2012-07-05 12:28:06 +00001074 public void callPlugins( final Dictionary props, final ServiceReference sr, final String configPid,
1075 final String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001076 {
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001077 ServiceReference[] plugins = null;
1078 try
1079 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001080 final String targetPid = (factoryPid == null) ? configPid : factoryPid;
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001081 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001082 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001083 }
1084 catch ( InvalidSyntaxException ise )
1085 {
1086 // no filter, no exception ...
1087 }
1088
1089 // abort early if there are no plugins
1090 if ( plugins == null || plugins.length == 0 )
1091 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001092 return;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001093 }
1094
1095 // sort the plugins by their service.cmRanking
Felix Meschberger007c50e2011-10-20 12:39:38 +00001096 if ( plugins.length > 1 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001097 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001098 Arrays.sort( plugins, RankingComparator.CM_RANKING );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001099 }
1100
1101 // call the plugins in order
Felix Meschberger007c50e2011-10-20 12:39:38 +00001102 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001103 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001104 ServiceReference pluginRef = plugins[i];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001105 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001106 if ( plugin != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001107 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001108 try
1109 {
1110 plugin.modifyConfiguration( sr, props );
1111 }
1112 catch ( Throwable t )
1113 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001114 log( LogService.LOG_ERROR, "Unexpected problem calling configuration plugin {0}", new Object[]
1115 { toString( pluginRef ), t } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001116 }
1117 finally
1118 {
1119 // ensure ungetting the plugin
1120 bundleContext.ungetService( pluginRef );
1121 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001122 ConfigurationImpl.setAutoProperties( props, configPid, factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001123 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001124 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001125 }
1126
1127
1128 /**
1129 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001130 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001131 * @param factoryPid
1132 * @return
1133 */
1134 private static String createPid( String factoryPid )
1135 {
Felix Meschberger417f66c2011-02-04 11:25:23 +00001136 Random ng = numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001137 if ( ng == null )
1138 {
Felix Meschberger417f66c2011-02-04 11:25:23 +00001139 // FELIX-2771 Secure Random not available on Mika
1140 try
1141 {
1142 ng = new SecureRandom();
1143 }
1144 catch ( Throwable t )
1145 {
1146 // fall back to Random
1147 ng = new Random();
1148 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001149 }
1150
1151 byte[] randomBytes = new byte[16];
1152 ng.nextBytes( randomBytes );
1153 randomBytes[6] &= 0x0f; /* clear version */
1154 randomBytes[6] |= 0x40; /* set to version 4 */
1155 randomBytes[8] &= 0x3f; /* clear variant */
1156 randomBytes[8] |= 0x80; /* set to IETF variant */
1157
1158 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
1159
1160 // prefix the new pid with the factory pid
1161 buf.append( factoryPid ).append( "." );
1162
1163 // serialize the UUID into the buffer
1164 for ( int i = 0; i < randomBytes.length; i++ )
1165 {
1166
1167 if ( i == 4 || i == 6 || i == 8 || i == 10 )
1168 {
1169 buf.append( '-' );
1170 }
1171
1172 int val = randomBytes[i] & 0xff;
1173 buf.append( Integer.toHexString( val >> 4 ) );
1174 buf.append( Integer.toHexString( val & 0xf ) );
1175 }
1176
1177 return buf.toString();
1178 }
1179
1180
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001181 public boolean isLogEnabled( int level )
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001182 {
1183 return level <= logLevel;
1184 }
1185
1186
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001187 public void log( int level, String format, Object[] args )
Felix Meschberger4f269292011-10-21 13:52:31 +00001188 {
1189 if ( isLogEnabled( level ) )
1190 {
1191 Throwable throwable = null;
1192 String message = format;
1193
1194 if ( args != null && args.length > 0 )
1195 {
1196 if ( args[args.length - 1] instanceof Throwable )
1197 {
1198 throwable = ( Throwable ) args[args.length - 1];
1199 }
1200 message = MessageFormat.format( format, args );
1201 }
1202
1203 log( level, message, throwable );
1204 }
1205 }
1206
1207
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001208 public void log( int level, String message, Throwable t )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001209 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001210 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +00001211 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001212 if ( log != null )
1213 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +00001214 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001215 return;
1216 }
1217
Felix Meschberger08282c32009-01-28 07:01:55 +00001218 // Otherwise only log if more serious than the configured level
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001219 if ( isLogEnabled( level ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001220 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001221 String code;
1222 switch ( level )
1223 {
1224 case LogService.LOG_INFO:
1225 code = "*INFO *";
1226 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001227
Felix Meschberger08282c32009-01-28 07:01:55 +00001228 case LogService.LOG_WARNING:
1229 code = "*WARN *";
1230 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001231
Felix Meschberger08282c32009-01-28 07:01:55 +00001232 case LogService.LOG_ERROR:
1233 code = "*ERROR*";
1234 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001235
Felix Meschberger08282c32009-01-28 07:01:55 +00001236 case LogService.LOG_DEBUG:
1237 default:
1238 code = "*DEBUG*";
1239 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001240
Felix Meschberger08282c32009-01-28 07:01:55 +00001241 System.err.println( code + " " + message );
1242 if ( t != null )
1243 {
1244 t.printStackTrace( System.err );
1245 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001246 }
1247 }
1248
Felix Meschberger851c6412009-08-16 18:43:26 +00001249
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001250 public static String toString( ServiceReference ref )
Felix Meschberger41cce522009-08-19 05:54:40 +00001251 {
1252 String[] ocs = ( String[] ) ref.getProperty( "objectClass" );
Felix Meschberger382a19b2012-07-03 09:45:14 +00001253 StringBuffer buf = new StringBuffer( "[" );
Felix Meschberger41cce522009-08-19 05:54:40 +00001254 for ( int i = 0; i < ocs.length; i++ )
1255 {
Felix Meschberger382a19b2012-07-03 09:45:14 +00001256 buf.append( ocs[i] );
Felix Meschberger41cce522009-08-19 05:54:40 +00001257 if ( i < ocs.length - 1 )
Felix Meschberger382a19b2012-07-03 09:45:14 +00001258 buf.append( ", " );
Felix Meschberger41cce522009-08-19 05:54:40 +00001259 }
1260
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001261 buf.append( ", id=" ).append( ref.getProperty( Constants.SERVICE_ID ) );
1262
1263 Bundle provider = ref.getBundle();
1264 if ( provider != null )
1265 {
1266 buf.append( ", bundle=" ).append( provider.getBundleId() );
Felix Meschberger0135b322011-11-16 12:30:22 +00001267 buf.append( '/' ).append( provider.getLocation() );
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001268 }
1269 else
1270 {
1271 buf.append( ", unregistered" );
1272 }
1273
1274 buf.append( "]" );
1275 return buf.toString();
Felix Meschberger41cce522009-08-19 05:54:40 +00001276 }
1277
Felix Meschbergerce67d732009-08-20 06:26:35 +00001278
Felix Meschberger007c50e2011-10-20 12:39:38 +00001279 /**
1280 * Checks whether the bundle is allowed to receive the configuration
1281 * with the given location binding.
1282 * <p>
1283 * This method implements the logic defined CM 1.4 / 104.4.1:
1284 * <ul>
1285 * <li>If the location is <code>null</code> (the configuration is not
1286 * bound yet), assume the bundle is allowed</li>
1287 * <li>If the location is a single location (no leading "?"), require
1288 * the bundle's location to match</li>
1289 * <li>If the location is a multi-location (leading "?"), assume the
1290 * bundle is allowed if there is no security manager. If there is a
1291 * security manager, check whether the bundle has "target" permission
1292 * on this location.</li>
1293 * </ul>
1294 */
1295 boolean canReceive( final Bundle bundle, final String location )
1296 {
1297 if ( location == null )
1298 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001299 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration=(unbound)", new Object[]
Felix Meschberger61207232011-11-17 10:06:45 +00001300 { bundle.getLocation() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001301 return true;
1302 }
1303 else if ( location.startsWith( "?" ) )
1304 {
1305 // multi-location
1306 if ( System.getSecurityManager() != null )
1307 {
Felix Meschberger61207232011-11-17 10:06:45 +00001308 final boolean hasPermission = bundle.hasPermission( new ConfigurationPermission( location,
1309 ConfigurationPermission.TARGET ) );
1310 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2} (SecurityManager check)",
1311 new Object[]
1312 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1313 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001314 }
Felix Meschberger61207232011-11-17 10:06:45 +00001315
1316 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration={1} (no SecurityManager)",
1317 new Object[]
1318 { bundle.getLocation(), location } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001319 return true;
1320 }
1321 else
1322 {
1323 // single location, must match
Felix Meschberger61207232011-11-17 10:06:45 +00001324 final boolean hasPermission = location.equals( bundle.getLocation() );
1325 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2}", new Object[]
1326 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1327 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001328 }
1329 }
1330
Felix Meschberger61207232011-11-17 10:06:45 +00001331
Felix Meschberger007c50e2011-10-20 12:39:38 +00001332 // ---------- inner classes
1333
Felix Meschberger007c50e2011-10-20 12:39:38 +00001334 /**
1335 * The <code>ManagedServiceUpdate</code> updates a freshly registered
1336 * <code>ManagedService</code> with a specific configuration. If a
1337 * ManagedService is registered with multiple PIDs an instance of this
1338 * class is used for each registered PID.
1339 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001340 private class ManagedServiceUpdate implements Runnable
1341 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001342 private final String[] pids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001343
Felix Meschberger41cce522009-08-19 05:54:40 +00001344 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001345
Felix Meschberger273985f2012-07-05 12:28:06 +00001346 ManagedServiceUpdate( String[] pids, ServiceReference sr )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001347 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001348 this.pids = pids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001349 this.sr = sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001350 }
1351
1352
1353 public void run()
1354 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001355 for ( String pid : this.pids )
1356 {
1357 try
1358 {
1359 final ConfigurationImpl config = getTargetedConfiguration( pid, this.sr );
1360 provide( pid, config );
1361 }
1362 catch ( IOException ioe )
1363 {
1364 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1365 { pid, ioe } );
1366 }
1367 catch ( Exception e )
1368 {
1369 log( LogService.LOG_ERROR, "Unexpected problem providing configuration {0} to service {1}",
1370 new Object[]
1371 { pid, ConfigurationManager.toString( this.sr ), e } );
1372 }
1373 }
1374 }
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001375
Felix Meschberger273985f2012-07-05 12:28:06 +00001376
1377 private void provide(final String servicePid, final ConfigurationImpl config)
1378 {
1379 // check configuration
1380 final TargetedPID configPid;
1381 final Dictionary properties;
1382 final long revision;
Felix Meschberger41cce522009-08-19 05:54:40 +00001383 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001384 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001385 synchronized ( config )
Felix Meschberger41243192009-01-14 19:59:58 +00001386 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001387 configPid = config.getPid();
1388 properties = config.getProperties( true );
1389 revision = config.getRevision();
Felix Meschberger41243192009-01-14 19:59:58 +00001390 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001391 }
1392 else
1393 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001394 // 104.5.3 ManagedService.updated must be called with null
1395 // if no configuration is available
Felix Meschberger273985f2012-07-05 12:28:06 +00001396 configPid = new TargetedPID( servicePid );
Felix Meschberger41cce522009-08-19 05:54:40 +00001397 properties = null;
Felix Meschberger273985f2012-07-05 12:28:06 +00001398 revision = -1;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001399 }
1400
Felix Meschberger273985f2012-07-05 12:28:06 +00001401 log( LogService.LOG_DEBUG, "Updating service {0} with configuration {1}@{2}", new Object[]
1402 { servicePid, configPid, new Long( revision ) } );
1403
1404 managedServiceTracker.provideConfiguration( sr, configPid, null, properties, revision);
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001405 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001406
Felix Meschberger432e3872008-03-07 14:58:57 +00001407 public String toString()
1408 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001409 return "ManagedService Update: pid=" + Arrays.asList( pids );
Felix Meschberger432e3872008-03-07 14:58:57 +00001410 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001411 }
1412
Felix Meschberger007c50e2011-10-20 12:39:38 +00001413 /**
1414 * The <code>ManagedServiceFactoryUpdate</code> updates a freshly
1415 * registered <code>ManagedServiceFactory</code> with a specific
1416 * configuration. If a ManagedServiceFactory is registered with
1417 * multiple PIDs an instance of this class is used for each registered
1418 * PID.
1419 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001420 private class ManagedServiceFactoryUpdate implements Runnable
1421 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001422 private final String[] factoryPids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001423
Felix Meschberger41cce522009-08-19 05:54:40 +00001424 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001425
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001426
Felix Meschberger273985f2012-07-05 12:28:06 +00001427 ManagedServiceFactoryUpdate( String[] factoryPids, ServiceReference sr )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001428 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001429 this.factoryPids = factoryPids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001430 this.sr = sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001431 }
1432
1433
1434 public void run()
1435 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001436 for ( String factoryPid : this.factoryPids )
1437 {
1438
1439 List<Factory> factories = null;
1440 try
1441 {
1442 factories = getTargetedFactories( factoryPid, sr );
1443 for ( Factory factory : factories )
1444 {
1445 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
1446 {
1447 final String pid = ( String ) pi.next();
1448 ConfigurationImpl cfg;
1449 try
1450 {
1451 cfg = getConfiguration( pid );
1452 }
1453 catch ( IOException ioe )
1454 {
1455 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1456 { pid, ioe } );
1457 continue;
1458 }
1459
1460 // sanity check on the configuration
1461 if ( cfg == null )
1462 {
1463 log( LogService.LOG_ERROR,
1464 "Configuration {0} referred to by factory {1} does not exist", new Object[]
1465 { pid, factoryPid } );
1466 factory.removePID( pid );
1467 factory.storeSilently();
1468 continue;
1469 }
1470 else if ( cfg.isNew() )
1471 {
1472 // Configuration has just been created but not yet updated
1473 // we currently just ignore it and have the update mechanism
1474 // provide the configuration to the ManagedServiceFactory
1475 // As of FELIX-612 (not storing new factory configurations)
1476 // this should not happen. We keep this for added stability
1477 // but raise the logging level to error.
1478 log( LogService.LOG_ERROR, "Ignoring new configuration pid={0}", new Object[]
1479 { pid } );
1480 continue;
1481 }
1482
1483 /*
1484 * this code would catch targeted factory PIDs;
1485 * since this is not expected any way, we can
1486 * leave this out
1487 */
1488 /*
1489 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1490 {
1491 log( LogService.LOG_ERROR,
1492 "Configuration {0} referred to by factory {1} seems to belong to factory {2}",
1493 new Object[]
1494 { pid, factoryPid, cfg.getFactoryPid() } );
1495 factory.removePID( pid );
1496 factory.storeSilently();
1497 continue;
1498 }
1499 */
1500
1501 provide( factoryPid, cfg );
1502 }
1503 }
1504 }
1505 catch ( IOException ioe )
1506 {
1507 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID {0}", new Object[]
1508 { factoryPid, ioe } );
1509 }
1510 }
1511 }
1512
1513
1514 private void provide(final String factoryPid, final ConfigurationImpl config) {
1515
1516 final Dictionary rawProperties;
1517 final long revision;
1518 synchronized ( config )
1519 {
1520 rawProperties = config.getProperties( true );
1521 revision = config.getRevision();
1522 }
1523
1524 log( LogService.LOG_DEBUG, "Updating service {0} with configuration {1}/{2}@{3}", new Object[]
1525 { factoryPid, config.getFactoryPid(), config.getPid(), new Long( revision ) } );
1526
1527 // CM 1.4 / 104.13.2.1
1528 final Bundle serviceBundle = this.sr.getBundle();
Felix Meschberger41243192009-01-14 19:59:58 +00001529 if ( serviceBundle == null )
1530 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001531 log(
1532 LogService.LOG_INFO,
1533 "ManagedServiceFactory for factory PID {0} seems to already have been unregistered, not updating with factory",
1534 new Object[]
1535 { factoryPid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001536 return;
1537 }
1538
Felix Meschberger273985f2012-07-05 12:28:06 +00001539 if ( !canReceive( serviceBundle, config.getBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001540 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001541 log( LogService.LOG_ERROR,
1542 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001543 new Object[]
Felix Meschberger273985f2012-07-05 12:28:06 +00001544 { config.getPid(), ConfigurationManager.toString( sr ), config.getBundleLocation() } );
1545
1546 // no service, really, bail out
1547 return;
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001548 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001549
1550 // 104.4.2 Dynamic Binding
1551 config.tryBindLocation( serviceBundle.getLocation() );
1552
1553 // update the service with the configuration (if non-null)
1554 if ( rawProperties != null )
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001555 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001556 log( LogService.LOG_DEBUG, "{0}: Updating configuration pid={1}", new Object[]
1557 { ConfigurationManager.toString( sr ), config.getPid() } );
1558 managedServiceFactoryTracker.provideConfiguration( sr, config.getPid(), config.getFactoryPid(),
1559 rawProperties, revision );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001560 }
1561 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001562
1563
Felix Meschberger432e3872008-03-07 14:58:57 +00001564 public String toString()
1565 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001566 return "ManagedServiceFactory Update: factoryPid=" + Arrays.asList( this.factoryPids );
Felix Meschberger432e3872008-03-07 14:58:57 +00001567 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001568 }
1569
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001570 private abstract class ConfigurationProvider<T> implements Runnable
1571 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001572
1573 protected final ConfigurationImpl config;
1574 protected final long revision;
1575 protected final Dictionary<String, ?> properties;
1576 protected final BaseTracker<T> helper;
1577
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001578
1579 protected ConfigurationProvider( final ConfigurationImpl config )
1580 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001581 synchronized ( config )
1582 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001583 this.config = config;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001584 this.revision = config.getRevision();
1585 this.properties = config.getProperties( true );
1586 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001587 this.helper = ( BaseTracker<T> ) ( ( config.getFactoryPid() == null ) ? managedServiceTracker
1588 : managedServiceFactoryTracker );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001589 }
1590
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001591
1592 protected TargetedPID getTargetedServicePid()
1593 {
1594 final TargetedPID factoryPid = this.config.getFactoryPid();
1595 if ( factoryPid != null )
1596 {
1597 return factoryPid;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001598 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001599 return this.config.getPid();
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001600 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001601
1602
1603 protected boolean provideReplacement( ServiceReference<T> sr )
1604 {
1605 if ( this.config.getFactoryPid() == null )
1606 {
1607 try
1608 {
Felix Meschberger1ff5c532012-07-08 18:23:08 +00001609 final String configPidString = this.helper.getServicePid( sr, this.config.getPid() );
1610 final ConfigurationImpl rc = getTargetedConfiguration( configPidString, sr );
Felix Meschberger273985f2012-07-05 12:28:06 +00001611 if ( rc != null )
1612 {
1613 final TargetedPID configPid;
1614 final Dictionary properties;
1615 final long revision;
Felix Meschbergercd5195f2012-07-05 17:17:45 +00001616 synchronized ( rc )
Felix Meschberger273985f2012-07-05 12:28:06 +00001617 {
Felix Meschbergercd5195f2012-07-05 17:17:45 +00001618 configPid = rc.getPid();
1619 properties = rc.getProperties( true );
1620 revision = rc.getRevision();
Felix Meschberger273985f2012-07-05 12:28:06 +00001621 }
1622
Felix Meschbergercd5195f2012-07-05 17:17:45 +00001623 helper.provideConfiguration( sr, configPid, null, properties, -revision );
Felix Meschberger273985f2012-07-05 12:28:06 +00001624
1625 return true;
1626 }
1627 }
1628 catch ( IOException ioe )
1629 {
1630 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1631 { this.config.getPid(), ioe } );
1632 }
1633 catch ( Exception e )
1634 {
1635 log( LogService.LOG_ERROR, "Unexpected problem providing configuration {0} to service {1}",
1636 new Object[]
1637 { this.config.getPid(), ConfigurationManager.toString( sr ), e } );
1638 }
1639 }
1640
1641 // factory or no replacement available
1642 return false;
1643 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001644 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001645
1646 /**
1647 * The <code>UpdateConfiguration</code> is used to update
1648 * <code>ManagedService[Factory]</code> services with the configuration
1649 * they are subscribed to. This may cause the configuration to be
1650 * supplied to multiple services.
1651 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001652 private class UpdateConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001653 {
1654
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001655 UpdateConfiguration( final ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001656 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001657 super( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001658 }
1659
1660
1661 public void run()
1662 {
Felix Meschberger61207232011-11-17 10:06:45 +00001663 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1664 { config.getPid(), new Long( revision ) } );
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001665
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001666 final List<ServiceReference<?>> srList = this.helper.getServices( getTargetedServicePid() );
1667 if ( !srList.isEmpty() )
Felix Meschberger41cce522009-08-19 05:54:40 +00001668 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001669 // optionally bind dynamically to the first service
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001670 config.tryBindLocation( srList.get( 0 ).getBundle().getLocation() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001671
1672 final String configBundleLocation = config.getBundleLocation();
1673
1674 // provide configuration to all services from the
1675 // correct bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001676 for (ServiceReference<?> ref : srList)
Felix Meschberger41cce522009-08-19 05:54:40 +00001677 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001678 final Bundle refBundle = ref.getBundle();
1679 if ( refBundle == null )
Felix Meschberger41cce522009-08-19 05:54:40 +00001680 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001681 log( LogService.LOG_DEBUG,
1682 "Service {0} seems to be unregistered concurrently (not providing configuration)",
1683 new Object[]
1684 { ConfigurationManager.toString( ref ) } );
1685 }
1686 else if ( canReceive( refBundle, configBundleLocation ) )
1687 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001688 helper.provideConfiguration( ref, this.config.getPid(), this.config.getFactoryPid(),
1689 this.properties, this.revision );
Felix Meschberger2444da62011-11-17 11:17:50 +00001690 }
1691 else
1692 {
1693 // CM 1.4 / 104.13.2.2
Felix Meschberger4f269292011-10-21 13:52:31 +00001694 log( LogService.LOG_ERROR,
1695 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1696 new Object[]
1697 { config.getPid(), ConfigurationManager.toString( ref ), configBundleLocation } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001698 }
1699
Felix Meschberger41cce522009-08-19 05:54:40 +00001700 }
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001701 }
Felix Meschberger137ee722011-11-16 09:51:59 +00001702 else if ( isLogEnabled( LogService.LOG_DEBUG ) )
1703 {
Felix Meschberger1ee888d2011-11-16 12:42:57 +00001704 log( LogService.LOG_DEBUG, "No ManagedService[Factory] registered for updates to configuration {0}",
Felix Meschberger137ee722011-11-16 09:51:59 +00001705 new Object[]
1706 { config.getPid() } );
1707 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001708 }
1709
1710
Felix Meschberger432e3872008-03-07 14:58:57 +00001711 public String toString()
1712 {
1713 return "Update: pid=" + config.getPid();
1714 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001715 }
1716
Felix Meschberger007c50e2011-10-20 12:39:38 +00001717
1718 /**
1719 * The <code>DeleteConfiguration</code> class is used to inform
1720 * <code>ManagedService[Factory]</code> services of a configuration
1721 * being deleted.
1722 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001723 private class DeleteConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001724 {
Felix Meschberger66423332007-08-22 08:46:34 +00001725
Felix Meschbergerc12db8c2009-08-19 06:43:59 +00001726 private final String configLocation;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001727
1728
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001729 DeleteConfiguration( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001730 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001731 /*
1732 * NOTE: We keep the configuration because it might be cleared just
1733 * after calling this method. The pid and factoryPid fields are
1734 * final and cannot be reset.
1735 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001736 super(config);
Felix Meschberger007c50e2011-10-20 12:39:38 +00001737 this.configLocation = config.getBundleLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001738 }
1739
1740
1741 public void run()
1742 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001743 List<ServiceReference<?>> srList = this.helper.getServices( getTargetedServicePid() );
1744 if ( !srList.isEmpty() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001745 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001746 for (ServiceReference<?> sr : srList)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001747 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001748 final Bundle srBundle = sr.getBundle();
1749 if ( srBundle == null )
1750 {
1751 log( LogService.LOG_DEBUG,
1752 "Service {0} seems to be unregistered concurrently (not removing configuration)",
1753 new Object[]
1754 { ConfigurationManager.toString( sr ) } );
1755 }
1756 else if ( canReceive( srBundle, configLocation ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001757 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001758 // revoke configuration unless a replacement
1759 // configuration can be provided
1760 if ( !this.provideReplacement( sr ) )
1761 {
1762 this.helper.removeConfiguration( sr, this.config.getPid(), this.config.getFactoryPid() );
1763 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001764 }
Felix Meschberger2444da62011-11-17 11:17:50 +00001765 else
1766 {
1767 // CM 1.4 / 104.13.2.2
1768 log( LogService.LOG_ERROR,
1769 "Cannot remove configuration {0} for {1}: No visibility to configuration bound to {2}",
1770 new Object[]
1771 { config.getPid(), ConfigurationManager.toString( sr ), configLocation } );
1772 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001773 }
1774 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001775
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001776 final TargetedPID factoryPid = config.getFactoryPid();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001777 if ( factoryPid != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001778 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001779 // remove the pid from the factory
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001780 final String pid = config.getPidString();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001781 try
1782 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001783 Factory factory = getOrCreateFactory( factoryPid.toString() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001784 factory.removePID( pid );
1785 factory.store();
1786 }
1787 catch ( IOException ioe )
1788 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001789 log( LogService.LOG_ERROR, "Failed removing {0} from the factory {1}", new Object[]
1790 { pid, factoryPid, ioe } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001791 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001792 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001793 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001794
Felix Meschberger432e3872008-03-07 14:58:57 +00001795 public String toString()
1796 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001797 return "Delete: pid=" + config.getPid();
Felix Meschberger432e3872008-03-07 14:58:57 +00001798 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001799 }
1800
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001801 private class LocationChanged extends ConfigurationProvider
Felix Meschberger007c50e2011-10-20 12:39:38 +00001802 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001803 private final String oldLocation;
1804
1805
1806 LocationChanged( ConfigurationImpl config, String oldLocation )
1807 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001808 super( config );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001809 this.oldLocation = oldLocation;
1810 }
1811
1812
1813 public void run()
1814 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001815 List<ServiceReference<?>> srList = helper.getServices( getTargetedServicePid() );
1816 if ( !srList.isEmpty() )
Felix Meschberger007c50e2011-10-20 12:39:38 +00001817 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001818 for (final ServiceReference<?> sr : srList)
Felix Meschberger007c50e2011-10-20 12:39:38 +00001819 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001820 final Bundle srBundle = sr.getBundle();
1821 if ( srBundle == null )
1822 {
1823 log( LogService.LOG_DEBUG,
1824 "Service {0} seems to be unregistered concurrently (not processing)", new Object[]
1825 { ConfigurationManager.toString( sr ) } );
1826 continue;
1827 }
1828
1829 final boolean wasVisible = canReceive( srBundle, oldLocation );
1830 final boolean isVisible = canReceive( srBundle, config.getBundleLocation() );
1831
1832 // make sure the config is dynamically bound to the first
1833 // service if the config has been unbound causing this update
1834 if ( isVisible )
1835 {
1836 config.tryBindLocation( srBundle.getLocation() );
1837 }
1838
Felix Meschberger007c50e2011-10-20 12:39:38 +00001839 if ( wasVisible && !isVisible )
1840 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001841 // revoke configuration unless a replacement
1842 // configuration can be provided
1843 if ( !this.provideReplacement( sr ) )
1844 {
1845 helper.removeConfiguration( sr, this.config.getPid(), this.config.getFactoryPid() );
1846 log( LogService.LOG_DEBUG, "Configuration {0} revoked from {1} (no more visibility)",
1847 new Object[]
1848 { config.getPid(), ConfigurationManager.toString( sr ) } );
1849 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001850 }
1851 else if ( !wasVisible && isVisible )
1852 {
1853 // call updated method
Felix Meschberger273985f2012-07-05 12:28:06 +00001854 helper.provideConfiguration( sr, this.config.getPid(), this.config.getFactoryPid(),
1855 this.properties, this.revision );
Felix Meschberger4f269292011-10-21 13:52:31 +00001856 log( LogService.LOG_DEBUG, "Configuration {0} provided to {1} (new visibility)", new Object[]
1857 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger35658d52011-10-20 21:43:58 +00001858 }
Felix Meschberger4f269292011-10-21 13:52:31 +00001859 else
Felix Meschberger35658d52011-10-20 21:43:58 +00001860 {
1861 // same visibility as before
Felix Meschberger4f269292011-10-21 13:52:31 +00001862 log( LogService.LOG_DEBUG, "Unmodified visibility to configuration {0} for {1}", new Object[]
1863 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001864 }
1865 }
1866 }
1867 }
1868
1869
1870 public String toString()
1871 {
1872 return "Location Changed (pid=" + config.getPid() + "): " + oldLocation + " ==> "
1873 + config.getBundleLocation();
1874 }
1875 }
1876
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001877 private class FireConfigurationEvent implements Runnable
1878 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001879 private final int type;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001880
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001881 private final String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001882
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001883 private final String factoryPid;
1884
1885 private final ServiceReference[] listenerReferences;
1886
1887 private final ConfigurationListener[] listeners;
1888
1889 private final Bundle[] listenerProvider;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001890
Felix Meschberger0770cad2012-06-11 12:36:52 +00001891 private ConfigurationEvent event;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001892
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001893 private FireConfigurationEvent( final int type, final String pid, final String factoryPid)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001894 {
1895 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001896 this.pid = pid;
1897 this.factoryPid = factoryPid;
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001898
1899 final ServiceReference[] srs = configurationListenerTracker.getServiceReferences();
1900 if ( srs == null || srs.length == 0 )
1901 {
1902 this.listenerReferences = null;
1903 this.listeners = null;
1904 this.listenerProvider = null;
1905 }
1906 else
1907 {
1908 this.listenerReferences = srs;
1909 this.listeners = new ConfigurationListener[srs.length];
1910 this.listenerProvider = new Bundle[srs.length];
1911 for ( int i = 0; i < srs.length; i++ )
1912 {
1913 this.listeners[i] = ( ConfigurationListener ) configurationListenerTracker.getService( srs[i] );
1914 this.listenerProvider[i] = srs[i].getBundle();
1915 }
1916 }
1917 }
1918
1919
Felix Meschberger0770cad2012-06-11 12:36:52 +00001920 void fireSynchronousEvents()
1921 {
1922 if ( hasConfigurationEventListeners() && getServiceReference() != null )
1923 {
1924 for ( int i = 0; i < this.listeners.length; i++ )
1925 {
1926 if ( this.listeners[i] instanceof SynchronousConfigurationListener )
1927 {
1928 sendEvent( i );
1929 }
1930 }
1931 }
1932 }
1933
1934
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001935 boolean hasConfigurationEventListeners()
1936 {
1937 return this.listenerReferences != null;
1938 }
1939
1940
1941 String getTypeName()
1942 {
1943 switch ( type )
1944 {
1945 case ConfigurationEvent.CM_DELETED:
1946 return "CM_DELETED";
1947 case ConfigurationEvent.CM_UPDATED:
1948 return "CM_UPDATED";
Felix Meschberger007c50e2011-10-20 12:39:38 +00001949 case ConfigurationEvent.CM_LOCATION_CHANGED:
1950 return "CM_LOCATION_CHANGED";
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001951 default:
1952 return "<UNKNOWN(" + type + ")>";
1953 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001954 }
1955
1956
1957 public void run()
1958 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001959 for ( int i = 0; i < listeners.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001960 {
Felix Meschberger0770cad2012-06-11 12:36:52 +00001961 sendEvent( i );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001962 }
1963 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001964
Felix Meschberger0770cad2012-06-11 12:36:52 +00001965
Felix Meschberger432e3872008-03-07 14:58:57 +00001966 public String toString()
1967 {
1968 return "Fire ConfigurationEvent: pid=" + pid;
1969 }
Felix Meschberger0770cad2012-06-11 12:36:52 +00001970
1971
1972 private ConfigurationEvent getConfigurationEvent()
1973 {
1974 if ( event == null )
1975 {
1976 this.event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
1977 }
1978 return event;
1979 }
1980
1981
1982 private void sendEvent( final int serviceIndex )
1983 {
1984 if ( listenerProvider[serviceIndex].getState() == Bundle.ACTIVE && this.listeners[serviceIndex] != null )
1985 {
1986 log( LogService.LOG_DEBUG, "Sending {0} event for {1} to {2}", new Object[]
1987 { getTypeName(), pid, ConfigurationManager.toString( listenerReferences[serviceIndex] ) } );
1988
1989 try
1990 {
1991 listeners[serviceIndex].configurationEvent( getConfigurationEvent() );
1992 }
1993 catch ( Throwable t )
1994 {
1995 log( LogService.LOG_ERROR, "Unexpected problem delivering configuration event to {0}", new Object[]
1996 { ConfigurationManager.toString( listenerReferences[serviceIndex] ), t } );
1997 }
1998 finally
1999 {
2000 this.listeners[serviceIndex] = null;
2001 }
2002 }
2003 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002004 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002005}
Felix Meschberger273985f2012-07-05 12:28:06 +00002006