blob: 27c0f7c1103ffd92c2f65b31559277097e1894ce [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;
Carsten Ziegeler41683982007-12-27 08:35:27 +000025import java.util.*;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000026
27import org.apache.felix.cm.PersistenceManager;
28import org.apache.felix.cm.file.FilePersistenceManager;
Carsten Ziegeler41683982007-12-27 08:35:27 +000029import org.osgi.framework.*;
30import org.osgi.service.cm.*;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000031import org.osgi.service.log.LogService;
32import org.osgi.util.tracker.ServiceTracker;
33
34
35/**
36 * The <code>ConfigurationManager</code> is the central class in this
37 * implementation of the Configuration Admin Service Specification. As such it
38 * has the following tasks:
39 * <ul>
40 * <li>It is a <code>BundleActivator</code> which is called when the bundle
41 * is started and stopped.
42 * <li>It is a <code>BundleListener</code> which gets informed when the
43 * states of bundles change. Mostly this is needed to unbind any bound
44 * configuration in case a bundle is uninstalled.
45 * <li>It is a <code>ServiceListener</code> which gets informed when
46 * <code>ManagedService</code> and <code>ManagedServiceFactory</code>
47 * services are registered and unregistered. This is used to provide
48 * configuration to these services. As a service listener it also listens for
49 * {@link PersistenceManager} instances being registered to support different
50 * configuration persistence layers.
51 * <li>A {@link ConfigurationAdminFactory} instance is registered as the
52 * <code>ConfigurationAdmin</code> service.
53 * <li>A {@link FilePersistenceManager} instance is registered as a default
54 * {@link PersistenceManager}.
55 * <li>Last but not least this instance manages all tasks laid out in the
56 * specification such as maintaining configuration, taking care of configuration
57 * events, etc.
58 * </ul>
59 * <p>
60 * The default {@link FilePersistenceManager} is configured with a configuration
61 * location taken from the <code>felix.cm.dir</code> framework property. If
62 * this property is not set the <code>config</code> directory in the current
63 * working directory as specified in the <code>user.dir</code> system property
64 * is used.
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000065 */
66public class ConfigurationManager implements BundleActivator, BundleListener
67{
68
69 /**
70 * The name of the bundle context property defining the location for the
71 * configuration files (value is "felix.cm.dir").
Felix Meschberger2fd5b582007-12-10 10:32:29 +000072 *
Carsten Ziegeler7853b9a2008-01-11 16:30:24 +000073 * @see #start(BundleContext)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000074 */
75 public static final String CM_CONFIG_DIR = "felix.cm.dir";
76
Felix Meschberger08282c32009-01-28 07:01:55 +000077 /**
78 * The name of the bundle context property defining the maximum log level
79 * (value is "felix.cm.loglevel"). The log level setting is only used if
80 * there is no OSGi LogService available. Otherwise this setting is ignored.
81 * <p>
82 * This value of this property is expected to be an integer number
83 * corresponding to the log level values of the OSGi LogService. That is 1
84 * for errors, 2 for warnings, 3 for informational messages and 4 for debug
85 * messages. The default value is 2, such that only warnings and errors are
86 * logged in the absence of a LogService.
87 */
88 public static final String CM_LOG_LEVEL = "felix.cm.loglevel";
89
Felix Meschberger85b355d2007-08-31 07:17:38 +000090 // The name of the LogService (not using the class, which might be missing)
91 private static final String LOG_SERVICE_NAME = "org.osgi.service.log.LogService";
Felix Meschberger2fd5b582007-12-10 10:32:29 +000092
Felix Meschberger08282c32009-01-28 07:01:55 +000093 private static final int CM_LOG_LEVEL_DEFAULT = 2;
Felix Meschberger5dfaa962009-08-14 19:26:01 +000094
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000095 // random number generator to create configuration PIDs for factory
96 // configurations
Felix Meschberger417f66c2011-02-04 11:25:23 +000097 private static Random numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000098
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000099 // the BundleContext of the Configuration Admin Service bundle
100 private BundleContext bundleContext;
101
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000102 // the service registration of the configuration admin
Felix Meschberger4b26df92011-02-01 12:41:45 +0000103 private volatile ServiceRegistration configurationAdminRegistration;
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000104
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000105 // the ServiceTracker to emit log services (see log(int, String, Throwable))
106 private ServiceTracker logTracker;
107
108 // the ConfigurationEvent listeners
109 private ServiceTracker configurationListenerTracker;
110
111 // service tracker for managed services
112 private ServiceTracker managedServiceTracker;
113
114 // service tracker for managed service factories
115 private ServiceTracker managedServiceFactoryTracker;
116
117 // PersistenceManager services
118 private ServiceTracker persistenceManagerTracker;
119
120 // the thread used to schedule tasks required to run asynchronously
121 private UpdateThread updateThread;
122
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000123 // the thread used to schedule events to be dispatched asynchronously
124 private UpdateThread eventThread;
125
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000126 /**
127 * The actual list of {@link PersistenceManager persistence managers} to use
128 * when looking for configuration data. This list is built from the
129 * {@link #persistenceManagerMap}, which is ordered according to the
130 * {@link RankingComparator}.
131 */
132 private PersistenceManager[] persistenceManagers;
133
134 // the persistenceManagerTracker.getTrackingCount when the
135 // persistenceManagers were last got
136 private int pmtCount;
137
138 // the cache of Factory instances mapped by their factory PID
Felix Meschberger6a698df2009-08-16 18:38:46 +0000139 private final Map factories = new HashMap();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000140
141 // the cache of Configuration instances mapped by their PID
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000142 // have this always set to prevent NPE on bundle shutdown
143 private final Map configurations = new HashMap();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000144
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000145 /**
146 * The map of dynamic configuration bindings. This maps the
147 * PID of the dynamically bound configuration or factory to its bundle
148 * location.
149 * <p>
150 * On bundle startup this map is loaded from persistence and validated
151 * against the locations of installed bundles: Entries pointing to bundle
152 * locations not currently installed are removed.
153 * <p>
154 * The map is written to persistence on each change.
155 */
156 private DynamicBindings dynamicBindings;
157
Felix Meschberger08282c32009-01-28 07:01:55 +0000158 // the maximum log level when no LogService is available
159 private int logLevel = CM_LOG_LEVEL_DEFAULT;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000160
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000161 // flag indicating whether BundleChange events should be consumed (FELIX-979)
162 private volatile boolean handleBundleEvents;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000163
Felix Meschberger623f7142012-01-31 07:13:37 +0000164 // flag indicating whether the manager is considered alive
165 private volatile boolean isActive;
166
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000167 public void start( BundleContext bundleContext )
168 {
169 // track the log service using a ServiceTracker
Felix Meschberger85b355d2007-08-31 07:17:38 +0000170 logTracker = new ServiceTracker( bundleContext, LOG_SERVICE_NAME , null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000171 logTracker.open();
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000172
Felix Meschberger08282c32009-01-28 07:01:55 +0000173 // assign the log level
174 String logLevelProp = bundleContext.getProperty( CM_LOG_LEVEL );
175 if ( logLevelProp == null )
176 {
177 logLevel = CM_LOG_LEVEL_DEFAULT;
178 }
179 else
180 {
181 try
182 {
183 logLevel = Integer.parseInt( logLevelProp );
184 }
185 catch ( NumberFormatException nfe )
186 {
187 logLevel = CM_LOG_LEVEL_DEFAULT;
188 }
189 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000190
191 // set up some fields
192 this.bundleContext = bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000193
194 // configurationlistener support
195 configurationListenerTracker = new ServiceTracker( bundleContext, ConfigurationListener.class.getName(), null );
196 configurationListenerTracker.open();
197
198 // initialize the asynchonous updater thread
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000199 ThreadGroup tg = new ThreadGroup( "Configuration Admin Service" );
200 tg.setDaemon( true );
201 this.updateThread = new UpdateThread( this, tg, "CM Configuration Updater" );
202 this.eventThread = new UpdateThread( this, tg, "CM Event Dispatcher" );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000203
204 // set up the location (might throw IllegalArgumentException)
205 try
206 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000207 FilePersistenceManager fpm = new FilePersistenceManager( bundleContext, bundleContext
208 .getProperty( CM_CONFIG_DIR ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000209 Hashtable props = new Hashtable();
210 props.put( Constants.SERVICE_PID, fpm.getClass().getName() );
211 props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
212 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
213 props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
214 bundleContext.registerService( PersistenceManager.class.getName(), fpm, props );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000215
216 // setup dynamic configuration bindings
217 dynamicBindings = new DynamicBindings( bundleContext, fpm );
218 }
219 catch ( IOException ioe )
220 {
221 log( LogService.LOG_ERROR, "Failure setting up dynamic configuration bindings", ioe );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000222 }
223 catch ( IllegalArgumentException iae )
224 {
225 log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
226 }
227
228 // register as bundle and service listener
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000229 handleBundleEvents = true;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000230 bundleContext.addBundleListener( this );
231
232 // get all persistence managers to begin with
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000233 pmtCount = 1; // make sure to get the persistence managers at least once
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000234 persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
235 persistenceManagerTracker.open();
236
Felix Meschberger623f7142012-01-31 07:13:37 +0000237 // consider alive now (before clients use Configuration Admin
238 // service registered in the next step)
239 isActive = true;
240
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000241 // create and register configuration admin - start after PM tracker ...
242 ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
243 Hashtable props = new Hashtable();
244 props.put( Constants.SERVICE_PID, "org.apache.felix.cm.ConfigurationAdmin" );
245 props.put( Constants.SERVICE_DESCRIPTION, "Configuration Admin Service Specification 1.2 Implementation" );
246 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000247 configurationAdminRegistration = bundleContext.registerService( ConfigurationAdmin.class.getName(), caf, props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000248
Felix Meschberger4b26df92011-02-01 12:41:45 +0000249 // start processing the event queues only after registering the service
250 // see FELIX-2813 for details
251 this.updateThread.start();
252 this.eventThread.start();
253
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000254 // start handling ManagedService[Factory] services
Carsten Ziegeler41683982007-12-27 08:35:27 +0000255 managedServiceTracker = new ManagedServiceTracker(this);
256 managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this);
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000257 }
258
259
260 public void stop( BundleContext bundleContext )
261 {
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000262
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000263 // stop handling bundle events immediately
264 handleBundleEvents = false;
265
Felix Meschberger4b26df92011-02-01 12:41:45 +0000266 // stop queue processing before unregistering the service
267 // see FELIX-2813 for details
268 if ( updateThread != null )
269 {
270 updateThread.terminate();
271 }
272 if ( eventThread != null )
273 {
274 eventThread.terminate();
275 }
276
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000277 // immediately unregister the Configuration Admin before cleaning up
Felix Meschberger10568352009-01-15 08:57:11 +0000278 // clearing the field before actually unregistering the service
279 // prevents IllegalStateException in getServiceReference() if
280 // the field is not null but the service already unregistered
281 if (configurationAdminRegistration != null) {
282 ServiceRegistration reg = configurationAdminRegistration;
283 configurationAdminRegistration = null;
284 reg.unregister();
285 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000286
Felix Meschberger623f7142012-01-31 07:13:37 +0000287 // consider inactive after unregistering such that during
288 // unregistration the manager is still alive and can react
289 isActive = false;
290
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000291 // stop handling ManagedService[Factory] services
292 managedServiceFactoryTracker.close();
293 managedServiceTracker.close();
294
295 // don't care for PersistenceManagers any more
296 persistenceManagerTracker.close();
297
298 // stop listening for events
299 bundleContext.removeBundleListener( this );
300
301 if ( configurationListenerTracker != null )
302 {
303 configurationListenerTracker.close();
304 }
305
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000306 if ( logTracker != null )
307 {
308 logTracker.close();
309 }
310
Felix Meschberger6a698df2009-08-16 18:38:46 +0000311 // just ensure the configuration cache is empty
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000312 synchronized ( configurations )
313 {
314 configurations.clear();
315 }
316
Felix Meschberger6a698df2009-08-16 18:38:46 +0000317 // just ensure the factory cache is empty
318 synchronized ( factories )
319 {
320 factories.clear();
321 }
322
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000323 this.bundleContext = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000324 }
325
326
Felix Meschberger623f7142012-01-31 07:13:37 +0000327 /**
328 * Returns <code>true</code> if this manager is considered active.
329 */
330 boolean isActive()
331 {
332 return isActive;
333 }
334
335
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000336 // ---------- Configuration caching support --------------------------------
337
338 ConfigurationImpl getCachedConfiguration( String pid )
339 {
340 synchronized ( configurations )
341 {
342 return ( ConfigurationImpl ) configurations.get( pid );
343 }
344 }
345
346
Felix Meschberger6a698df2009-08-16 18:38:46 +0000347 ConfigurationImpl[] getCachedConfigurations()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000348 {
349 synchronized ( configurations )
350 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000351 return ( ConfigurationImpl[] ) configurations.values().toArray(
352 new ConfigurationImpl[configurations.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000353 }
354 }
355
356
Felix Meschberger2941ef92007-08-20 13:15:16 +0000357 ConfigurationImpl cacheConfiguration( ConfigurationImpl configuration )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000358 {
359 synchronized ( configurations )
360 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000361 Object existing = configurations.get( configuration.getPid() );
362 if ( existing != null )
363 {
364 return ( ConfigurationImpl ) existing;
365 }
366
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000367 configurations.put( configuration.getPid(), configuration );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000368 return configuration;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000369 }
370 }
371
372
373 void removeConfiguration( ConfigurationImpl configuration )
374 {
375 synchronized ( configurations )
376 {
377 configurations.remove( configuration.getPid() );
378 }
379 }
380
381
Felix Meschberger6a698df2009-08-16 18:38:46 +0000382 Factory getCachedFactory( String factoryPid )
383 {
384 synchronized ( factories )
385 {
386 return ( Factory ) factories.get( factoryPid );
387 }
388 }
389
390
391 Factory[] getCachedFactories()
392 {
393 synchronized ( factories )
394 {
395 return ( Factory[] ) factories.values().toArray( new Factory[factories.size()] );
396 }
397 }
398
399
400 void cacheFactory( Factory factory )
401 {
402 synchronized ( factories )
403 {
404 factories.put( factory.getFactoryPid(), factory );
405 }
406 }
407
408
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000409 // ---------- ConfigurationAdminImpl support
Felix Meschberger6a698df2009-08-16 18:38:46 +0000410
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000411 void setDynamicBundleLocation( final String pid, final String location )
412 {
413 if ( dynamicBindings != null )
414 {
415 try
416 {
417 dynamicBindings.putLocation( pid, location );
418 }
419 catch ( IOException ioe )
420 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000421 log( LogService.LOG_ERROR, "Failed storing dynamic configuration binding for {0} to {1}", new Object[]
422 { pid, location, ioe } );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000423 }
424 }
425 }
426
427
428 String getDynamicBundleLocation( final String pid )
429 {
430 if ( dynamicBindings != null )
431 {
432 return dynamicBindings.getLocation( pid );
433 }
434
435 return null;
436 }
437
438
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000439 ConfigurationImpl createFactoryConfiguration( String factoryPid, String location ) throws IOException
440 {
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000441 return cacheConfiguration( createConfiguration( createPid( factoryPid ), factoryPid, location ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000442 }
443
444
Felix Meschbergerad949872011-11-16 10:34:54 +0000445 /**
446 * Returns the {@link ConfigurationImpl} with the given PID if
447 * available in the internal cache or from any persistence manager.
448 * Otherwise <code>null</code> is returned.
449 *
450 * @param pid The PID for which to return the configuration
451 * @return The configuration or <code>null</code> if non exists
452 * @throws IOException If an error occurrs reading from a persistence
453 * manager.
454 */
455 ConfigurationImpl getConfiguration( String pid ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000456 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000457 ConfigurationImpl config = getCachedConfiguration( pid );
458 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000459 {
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000460 log( LogService.LOG_DEBUG, "Found cached configuration {0} bound to {1}", new Object[]
461 { pid, config.getBundleLocation() } );
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000462
463 config.ensureFactoryConfigPersisted();
464
Felix Meschberger2941ef92007-08-20 13:15:16 +0000465 return config;
466 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000467
Felix Meschberger2941ef92007-08-20 13:15:16 +0000468 PersistenceManager[] pmList = getPersistenceManagers();
469 for ( int i = 0; i < pmList.length; i++ )
470 {
471 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000472 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000473 Dictionary props = pmList[i].load( pid );
474 config = new ConfigurationImpl( this, pmList[i], props );
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000475 log( LogService.LOG_DEBUG, "Found existing configuration {0} bound to {1}", new Object[]
476 { pid, config.getBundleLocation() } );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000477 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000478 }
479 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000480
Felix Meschberger2941ef92007-08-20 13:15:16 +0000481 // neither the cache nor any persistence manager has configuration
482 return null;
483 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000484
485
Felix Meschbergerad949872011-11-16 10:34:54 +0000486 /**
487 * Creates a regular (non-factory) configuration for the given PID
488 * setting the bundle location accordingly.
489 * <p>
490 * This method assumes the configuration to not exist yet and will
491 * create it without further checking.
492 *
493 * @param pid The PID of the new configuration
494 * @param bundleLocation The location to set on the new configuration.
495 * This may be <code>null</code> to not bind the configuration
496 * yet.
497 * @return The new configuration persisted in the first persistence
498 * manager.
499 * @throws IOException If an error occurrs writing the configuration
500 * to the persistence.
501 */
502 ConfigurationImpl createConfiguration( String pid, String bundleLocation ) throws IOException
Felix Meschberger2941ef92007-08-20 13:15:16 +0000503 {
504 // check for existing (cached or persistent) configuration
Felix Meschbergerad949872011-11-16 10:34:54 +0000505 ConfigurationImpl config = getConfiguration( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000506 if ( config != null )
507 {
508 return config;
509 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000510
Felix Meschberger2941ef92007-08-20 13:15:16 +0000511 // else create new configuration also setting the bundle location
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000512 // and cache the new configuration
513 config = createConfiguration( pid, null, bundleLocation );
514 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000515 }
516
517
518 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
519 throws IOException, InvalidSyntaxException
520 {
521 Filter filter = null;
522 if ( filterString != null )
523 {
524 filter = bundleContext.createFilter( filterString );
525 }
526
Felix Meschberger4f269292011-10-21 13:52:31 +0000527 log( LogService.LOG_DEBUG, "Listing configurations matching {0}", new Object[]
528 { filterString } );
529
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000530 List configList = new ArrayList();
531
532 PersistenceManager[] pmList = getPersistenceManagers();
533 for ( int i = 0; i < pmList.length; i++ )
534 {
535 Enumeration configs = pmList[i].getDictionaries();
536 while ( configs.hasMoreElements() )
537 {
538 Dictionary config = ( Dictionary ) configs.nextElement();
539
540 // ignore non-Configuration dictionaries
Felix Meschberger86a0d172007-07-04 07:15:01 +0000541 String pid = ( String ) config.get( Constants.SERVICE_PID );
542 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000543 {
544 continue;
545 }
546
Felix Meschberger007c50e2011-10-20 12:39:38 +0000547 // CM 1.4 / 104.13.2.3 Permission required
548 if ( !configurationAdmin.hasPermission( ( String ) config
549 .get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000550 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000551 log(
552 LogService.LOG_DEBUG,
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000553 "Omitting configuration {0}: No permission for bundle {1} on configuration bound to {2}",
Felix Meschberger4f269292011-10-21 13:52:31 +0000554 new Object[]
555 { config.get( Constants.SERVICE_PID ), configurationAdmin.getBundle().getLocation(),
556 config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000557 continue;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000558 }
559
560 // check filter
561 if ( filter == null || filter.match( config ) )
562 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000563 // ensure the service.pid and returned a cached config if available
564 ConfigurationImpl cfg = getCachedConfiguration( pid );
565 if ( cfg == null )
566 {
567 cfg = new ConfigurationImpl( this, pmList[i], config );
568 }
569
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000570 // FELIX-611: Ignore configuration objects without props
571 if ( !cfg.isNew() )
572 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000573 log( LogService.LOG_DEBUG, "Adding configuration {0}", new Object[]
574 { config.get( Constants.SERVICE_PID ) } );
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000575 configList.add( cfg );
576 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000577 else
578 {
579 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Is new", new Object[]
580 { config.get( Constants.SERVICE_PID ) } );
581 }
582 } else {
583 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Does not match filter", new Object[]
584 { config.get( Constants.SERVICE_PID ) } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000585 }
586 }
587 }
588
Felix Meschberger8faceff2007-07-04 07:19:48 +0000589 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000590 .size()] );
591 }
592
593
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000594 void deleted( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000595 {
596 // remove the configuration from the cache
597 removeConfiguration( config );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000598 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, config.getPid(), config.getFactoryPid() );
599 updateThread.schedule( new DeleteConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000600 log( LogService.LOG_DEBUG, "DeleteConfiguration({0}) scheduled", new Object[]
601 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000602 }
603
604
Felix Meschbergerce67d732009-08-20 06:26:35 +0000605 void updated( ConfigurationImpl config, boolean fireEvent )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000606 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000607 if ( fireEvent )
608 {
609 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPid(), config.getFactoryPid() );
610 }
611 updateThread.schedule( new UpdateConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000612 log( LogService.LOG_DEBUG, "UpdateConfiguration({0}) scheduled", new Object[]
613 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000614 }
615
616
Felix Meschberger007c50e2011-10-20 12:39:38 +0000617 void locationChanged( ConfigurationImpl config, String oldLocation )
618 {
619 fireConfigurationEvent( ConfigurationEvent.CM_LOCATION_CHANGED, config.getPid(), config.getFactoryPid() );
Felix Meschberger35658d52011-10-20 21:43:58 +0000620 if ( oldLocation != null && !config.isNew() )
Felix Meschberger007c50e2011-10-20 12:39:38 +0000621 {
622 updateThread.schedule( new LocationChanged( config, oldLocation ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000623 log( LogService.LOG_DEBUG, "LocationChanged({0}, {1}=>{2}) scheduled", new Object[]
624 { config.getPid(), oldLocation, config.getBundleLocation() } );
Felix Meschberger35658d52011-10-20 21:43:58 +0000625 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000626 else
Felix Meschberger35658d52011-10-20 21:43:58 +0000627 {
628 log( LogService.LOG_DEBUG,
Felix Meschberger4f269292011-10-21 13:52:31 +0000629 "LocationChanged not scheduled for {0} (old location is null or configuration is new)", new Object[]
630 { config.getPid() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000631 }
632 }
633
634
Felix Meschberger66423332007-08-22 08:46:34 +0000635 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000636 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000637 FireConfigurationEvent event = new FireConfigurationEvent( type, pid, factoryPid );
638 if ( event.hasConfigurationEventListeners() )
639 {
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000640 eventThread.schedule( event );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000641 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000642 else
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000643 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000644 log( LogService.LOG_DEBUG, "No ConfigurationListeners to send {0} event to.", new Object[]
645 { event.getTypeName() } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000646 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000647 }
648
649
650 // ---------- BundleListener -----------------------------------------------
651
652 public void bundleChanged( BundleEvent event )
653 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000654 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000655 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000656 final String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000657
Felix Meschberger6a698df2009-08-16 18:38:46 +0000658 // we only reset dynamic bindings, which are only present in
659 // cached configurations, hence only consider cached configs here
660 final ConfigurationImpl[] configs = getCachedConfigurations();
661 for ( int i = 0; i < configs.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000662 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000663 final ConfigurationImpl cfg = configs[i];
Felix Meschberger41cce522009-08-19 05:54:40 +0000664 if ( location.equals( cfg.getDynamicBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000665 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000666 cfg.setDynamicBundleLocation( null, true );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000667 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000668 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000669 }
670 }
671
672
673 // ---------- internal -----------------------------------------------------
674
675 private PersistenceManager[] getPersistenceManagers()
676 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000677 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
678 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000679 {
680
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000681 List pmList = new ArrayList();
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000682 PersistenceManager[] pm;
683
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000684 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
685 if ( refs == null || refs.length == 0 )
686 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000687 pm = new PersistenceManager[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000688 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000689 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000690 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000691 // sort the references according to the cmRanking property
Felix Meschberger007c50e2011-10-20 12:39:38 +0000692 if ( refs.length > 1 )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000693 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000694 Arrays.sort( refs, RankingComparator.SRV_RANKING );
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000695 }
696
697 // create the service array from the sorted set of referenecs
Felix Meschberger007c50e2011-10-20 12:39:38 +0000698 for ( int i = 0; i < refs.length; i++ )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000699 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000700 Object service = persistenceManagerTracker.getService( refs[i] );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000701 if ( service != null )
702 {
Felix Meschbergera86cdfc2010-08-25 09:32:36 +0000703 pmList.add( new CachingPersistenceManagerProxy( ( PersistenceManager ) service ) );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000704 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000705 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000706
707 pm = ( PersistenceManager[] ) pmList.toArray( new PersistenceManager[pmList.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000708 }
709
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000710 pmtCount = pm.length;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000711 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000712 }
713
714 return persistenceManagers;
715 }
716
717
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000718 private ServiceReference getServiceReference()
719 {
720 ServiceRegistration reg = configurationAdminRegistration;
721 return ( reg != null ) ? reg.getReference() : null;
722 }
723
724
Felix Meschberger05d89e12011-11-03 23:37:10 +0000725 /**
726 * Configures the ManagedService and returns the service.pid
727 * service property as a String[], which may be <code>null</code> if
728 * the ManagedService does not have such a property.
729 */
730 private void configure( String[] pids, ServiceReference sr, ManagedService service )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000731 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000732 if ( pids != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000733 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +0000734 if ( isLogEnabled( LogService.LOG_DEBUG ) )
735 {
736 log( LogService.LOG_DEBUG, "configure(ManagedService {0})", new Object[]
737 { toString( sr ) } );
738 }
739
Felix Meschberger851c6412009-08-16 18:43:26 +0000740 for ( int i = 0; i < pids.length; i++ )
741 {
742 ManagedServiceUpdate update = new ManagedServiceUpdate( pids[i], sr, service );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000743 updateThread.schedule( update );
Felix Meschberger4f269292011-10-21 13:52:31 +0000744 log( LogService.LOG_DEBUG, "ManagedServiceUpdate({0}) scheduled", new Object[]
745 { pids[i] } );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000746 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000747 }
Felix Meschberger851c6412009-08-16 18:43:26 +0000748 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000749
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000750
Felix Meschberger05d89e12011-11-03 23:37:10 +0000751 /**
752 * Configures the ManagedServiceFactory and returns the service.pid
753 * service property as a String[], which may be <code>null</code> if
754 * the ManagedServiceFactory does not have such a property.
755 */
756 private void configure( String[] pids, ServiceReference sr, ManagedServiceFactory service )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000757 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000758 if ( pids != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000759 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +0000760 if ( isLogEnabled( LogService.LOG_DEBUG ) )
761 {
762 log( LogService.LOG_DEBUG, "configure(ManagedServiceFactory {0})", new Object[]
763 { toString( sr ) } );
764 }
765
Felix Meschberger851c6412009-08-16 18:43:26 +0000766 for ( int i = 0; i < pids.length; i++ )
767 {
768 ManagedServiceFactoryUpdate update = new ManagedServiceFactoryUpdate( pids[i], sr, service );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000769 updateThread.schedule( update );
Felix Meschberger4f269292011-10-21 13:52:31 +0000770 log( LogService.LOG_DEBUG, "ManagedServiceFactoryUpdate({0}) scheduled", new Object[]
771 { pids[i] } );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000772 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000773 }
Felix Meschberger851c6412009-08-16 18:43:26 +0000774 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000775
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000776
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000777 /**
778 * Factory method to create a new configuration object. The configuration
779 * object returned is not stored in configuration cache and only persisted
780 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000781 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000782 * @param pid
783 * The PID of the new configuration object. Must not be
784 * <code>null</code>.
785 * @param factoryPid
786 * The factory PID of the new configuration. Not
Felix Meschberger6a698df2009-08-16 18:38:46 +0000787 * <code>null</code> if the new configuration object belongs to a
788 * factory. The configuration object will not be persisted if
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000789 * this parameter is not <code>null</code>.
790 * @param bundleLocation
791 * The bundle location of the bundle to which the configuration
Felix Meschberger6a698df2009-08-16 18:38:46 +0000792 * belongs or <code>null</code> if the configuration is not bound
793 * yet.
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000794 * @return The new configuration object
795 * @throws IOException
796 * May be thrown if an error occurrs persisting the new
797 * configuration object.
798 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000799 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000800 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000801 log( LogService.LOG_DEBUG, "createConfiguration({0}, {1}, {2})", new Object[]
802 { pid, factoryPid, bundleLocation } );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000803 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000804 }
805
806
807 Factory getFactory( String factoryPid ) throws IOException
808 {
Felix Meschbergerf4631322008-03-10 12:32:35 +0000809 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000810 if ( factory != null )
811 {
812 return factory;
813 }
814
815 PersistenceManager[] pmList = getPersistenceManagers();
816 for ( int i = 0; i < pmList.length; i++ )
817 {
818 if ( Factory.exists( pmList[i], factoryPid ) )
819 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000820 factory = Factory.load( this, pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000821 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000822 return factory;
823 }
824 }
825
826 // if getting here, there is no configuration yet, optionally create new
827 return createFactory( factoryPid );
828 }
829
830
831 Factory createFactory( String factoryPid )
832 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000833 Factory factory = new Factory( this, getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000834 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000835 return factory;
836 }
837
838
Felix Meschberger2941ef92007-08-20 13:15:16 +0000839 /**
840 * Calls the registered configuration plugins on the given configuration
Felix Meschberger41cce522009-08-19 05:54:40 +0000841 * properties from the given configuration object unless the configuration
842 * has just been created and not been updated yet.
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000843 *
Felix Meschberger41cce522009-08-19 05:54:40 +0000844 * @param props The configuraiton properties run through the registered
845 * ConfigurationPlugin services. This may be <code>null</code>
846 * in which case this method just immediately returns.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000847 * @param targetPid The identification of the configuration update used to
848 * select the plugins according to their cm.target service
849 * property
Felix Meschberger2941ef92007-08-20 13:15:16 +0000850 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000851 * is to be updated with configuration
Felix Meschberger2941ef92007-08-20 13:15:16 +0000852 * @param cfg The configuration object whose properties have to be passed
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000853 * through the plugins
Felix Meschberger2941ef92007-08-20 13:15:16 +0000854 */
Felix Meschberger41cce522009-08-19 05:54:40 +0000855 private void callPlugins( final Dictionary props, final String targetPid, final ServiceReference sr,
856 final ConfigurationImpl cfg )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000857 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000858 // guard against NPE for new configuration never updated
859 if (props == null) {
Felix Meschberger41cce522009-08-19 05:54:40 +0000860 return;
Felix Meschberger2941ef92007-08-20 13:15:16 +0000861 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000862
863 ServiceReference[] plugins = null;
864 try
865 {
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000866 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000867 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000868 }
869 catch ( InvalidSyntaxException ise )
870 {
871 // no filter, no exception ...
872 }
873
874 // abort early if there are no plugins
875 if ( plugins == null || plugins.length == 0 )
876 {
Felix Meschberger41cce522009-08-19 05:54:40 +0000877 return;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000878 }
879
880 // sort the plugins by their service.cmRanking
Felix Meschberger007c50e2011-10-20 12:39:38 +0000881 if ( plugins.length > 1 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000882 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000883 Arrays.sort( plugins, RankingComparator.CM_RANKING );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000884 }
885
886 // call the plugins in order
Felix Meschberger007c50e2011-10-20 12:39:38 +0000887 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000888 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000889 ServiceReference pluginRef = plugins[i];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000890 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000891 if ( plugin != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000892 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000893 try
894 {
895 plugin.modifyConfiguration( sr, props );
896 }
897 catch ( Throwable t )
898 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000899 log( LogService.LOG_ERROR, "Unexpected problem calling configuration plugin {0}", new Object[]
900 { toString( pluginRef ), t } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000901 }
902 finally
903 {
904 // ensure ungetting the plugin
905 bundleContext.ungetService( pluginRef );
906 }
907 cfg.setAutoProperties( props, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000908 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000909 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000910 }
911
912
913 /**
914 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000915 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000916 * @param factoryPid
917 * @return
918 */
919 private static String createPid( String factoryPid )
920 {
Felix Meschberger417f66c2011-02-04 11:25:23 +0000921 Random ng = numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000922 if ( ng == null )
923 {
Felix Meschberger417f66c2011-02-04 11:25:23 +0000924 // FELIX-2771 Secure Random not available on Mika
925 try
926 {
927 ng = new SecureRandom();
928 }
929 catch ( Throwable t )
930 {
931 // fall back to Random
932 ng = new Random();
933 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000934 }
935
936 byte[] randomBytes = new byte[16];
937 ng.nextBytes( randomBytes );
938 randomBytes[6] &= 0x0f; /* clear version */
939 randomBytes[6] |= 0x40; /* set to version 4 */
940 randomBytes[8] &= 0x3f; /* clear variant */
941 randomBytes[8] |= 0x80; /* set to IETF variant */
942
943 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
944
945 // prefix the new pid with the factory pid
946 buf.append( factoryPid ).append( "." );
947
948 // serialize the UUID into the buffer
949 for ( int i = 0; i < randomBytes.length; i++ )
950 {
951
952 if ( i == 4 || i == 6 || i == 8 || i == 10 )
953 {
954 buf.append( '-' );
955 }
956
957 int val = randomBytes[i] & 0xff;
958 buf.append( Integer.toHexString( val >> 4 ) );
959 buf.append( Integer.toHexString( val & 0xf ) );
960 }
961
962 return buf.toString();
963 }
964
965
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000966 boolean isLogEnabled( int level )
967 {
968 return level <= logLevel;
969 }
970
971
Felix Meschberger4f269292011-10-21 13:52:31 +0000972 void log( int level, String format, Object[] args )
973 {
974 if ( isLogEnabled( level ) )
975 {
976 Throwable throwable = null;
977 String message = format;
978
979 if ( args != null && args.length > 0 )
980 {
981 if ( args[args.length - 1] instanceof Throwable )
982 {
983 throwable = ( Throwable ) args[args.length - 1];
984 }
985 message = MessageFormat.format( format, args );
986 }
987
988 log( level, message, throwable );
989 }
990 }
991
992
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000993 void log( int level, String message, Throwable t )
994 {
Felix Meschberger08282c32009-01-28 07:01:55 +0000995 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +0000996 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000997 if ( log != null )
998 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000999 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001000 return;
1001 }
1002
Felix Meschberger08282c32009-01-28 07:01:55 +00001003 // Otherwise only log if more serious than the configured level
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001004 if ( isLogEnabled( level ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001005 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001006 String code;
1007 switch ( level )
1008 {
1009 case LogService.LOG_INFO:
1010 code = "*INFO *";
1011 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001012
Felix Meschberger08282c32009-01-28 07:01:55 +00001013 case LogService.LOG_WARNING:
1014 code = "*WARN *";
1015 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001016
Felix Meschberger08282c32009-01-28 07:01:55 +00001017 case LogService.LOG_ERROR:
1018 code = "*ERROR*";
1019 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001020
Felix Meschberger08282c32009-01-28 07:01:55 +00001021 case LogService.LOG_DEBUG:
1022 default:
1023 code = "*DEBUG*";
1024 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001025
Felix Meschberger08282c32009-01-28 07:01:55 +00001026 System.err.println( code + " " + message );
1027 if ( t != null )
1028 {
1029 t.printStackTrace( System.err );
1030 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001031 }
1032 }
1033
Felix Meschberger851c6412009-08-16 18:43:26 +00001034
1035 /**
1036 * Returns the <code>service.pid</code> property of the service reference as
1037 * an array of strings or <code>null</code> if the service reference does
1038 * not have a service PID property.
1039 * <p>
1040 * The service.pid property may be a single string, in which case a single
1041 * element array is returned. If the property is an array of string, this
1042 * array is returned. If the property is a collection it is assumed to be a
1043 * collection of strings and the collection is converted to an array to be
1044 * returned. Otherwise (also if the property is not set) <code>null</code>
1045 * is returned.
1046 *
1047 * @throws NullPointerException
1048 * if reference is <code>null</code>
1049 * @throws ArrayStoreException
1050 * if the service pid is a collection and not all elements are
1051 * strings.
1052 */
1053 static String[] getServicePid( ServiceReference reference )
1054 {
1055 Object pidObj = reference.getProperty( Constants.SERVICE_PID );
1056 if ( pidObj instanceof String )
1057 {
1058 return new String[]
1059 { ( String ) pidObj };
1060 }
1061 else if ( pidObj instanceof String[] )
1062 {
1063 return ( String[] ) pidObj;
1064 }
1065 else if ( pidObj instanceof Collection )
1066 {
1067 Collection pidCollection = ( Collection ) pidObj;
1068 return ( String[] ) pidCollection.toArray( new String[pidCollection.size()] );
1069 }
1070
1071 return null;
1072 }
1073
Felix Meschberger41cce522009-08-19 05:54:40 +00001074
1075 static String toString( ServiceReference ref )
1076 {
1077 String[] ocs = ( String[] ) ref.getProperty( "objectClass" );
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001078 StringBuffer buf = new StringBuffer("[");
Felix Meschberger41cce522009-08-19 05:54:40 +00001079 for ( int i = 0; i < ocs.length; i++ )
1080 {
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001081 buf.append(ocs[i]);
Felix Meschberger41cce522009-08-19 05:54:40 +00001082 if ( i < ocs.length - 1 )
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001083 buf.append(", ");
Felix Meschberger41cce522009-08-19 05:54:40 +00001084 }
1085
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001086 buf.append( ", id=" ).append( ref.getProperty( Constants.SERVICE_ID ) );
1087
1088 Bundle provider = ref.getBundle();
1089 if ( provider != null )
1090 {
1091 buf.append( ", bundle=" ).append( provider.getBundleId() );
Felix Meschberger0135b322011-11-16 12:30:22 +00001092 buf.append( '/' ).append( provider.getLocation() );
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001093 }
1094 else
1095 {
1096 buf.append( ", unregistered" );
1097 }
1098
1099 buf.append( "]" );
1100 return buf.toString();
Felix Meschberger41cce522009-08-19 05:54:40 +00001101 }
1102
Felix Meschbergerce67d732009-08-20 06:26:35 +00001103
1104 void handleCallBackError( final Throwable error, final ServiceReference target, final ConfigurationImpl config )
1105 {
1106 if ( error instanceof ConfigurationException )
1107 {
1108 final ConfigurationException ce = ( ConfigurationException ) error;
1109 if ( ce.getProperty() != null )
1110 {
Felix Meschberger93edd662012-01-31 07:17:46 +00001111 log( LogService.LOG_ERROR, "{0}: Updating property {1} of configuration {2} caused a problem: {3}",
Felix Meschberger4f269292011-10-21 13:52:31 +00001112 new Object[]
Felix Meschberger93edd662012-01-31 07:17:46 +00001113 { toString( target ), ce.getProperty(), config.getPid(), ce.getReason(), ce } );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001114 }
1115 else
1116 {
Felix Meschberger93edd662012-01-31 07:17:46 +00001117 log( LogService.LOG_ERROR, "{0}: Updating configuration {1} caused a problem: {2}", new Object[]
1118 { toString( target ), config.getPid(), ce.getReason(), ce } );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001119 }
1120 }
1121 else
1122 {
1123 {
Felix Meschberger93edd662012-01-31 07:17:46 +00001124 log( LogService.LOG_ERROR, "{0}: Unexpected problem updating configuration {1}", new Object[]
Felix Meschberger4f269292011-10-21 13:52:31 +00001125 { toString( target ), config, error } );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001126 }
1127
1128 }
1129 }
1130
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001131
Felix Meschberger007c50e2011-10-20 12:39:38 +00001132 /**
1133 * Checks whether the bundle is allowed to receive the configuration
1134 * with the given location binding.
1135 * <p>
1136 * This method implements the logic defined CM 1.4 / 104.4.1:
1137 * <ul>
1138 * <li>If the location is <code>null</code> (the configuration is not
1139 * bound yet), assume the bundle is allowed</li>
1140 * <li>If the location is a single location (no leading "?"), require
1141 * the bundle's location to match</li>
1142 * <li>If the location is a multi-location (leading "?"), assume the
1143 * bundle is allowed if there is no security manager. If there is a
1144 * security manager, check whether the bundle has "target" permission
1145 * on this location.</li>
1146 * </ul>
1147 */
1148 boolean canReceive( final Bundle bundle, final String location )
1149 {
1150 if ( location == null )
1151 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001152 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration=(unbound)", new Object[]
Felix Meschberger61207232011-11-17 10:06:45 +00001153 { bundle.getLocation() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001154 return true;
1155 }
1156 else if ( location.startsWith( "?" ) )
1157 {
1158 // multi-location
1159 if ( System.getSecurityManager() != null )
1160 {
Felix Meschberger61207232011-11-17 10:06:45 +00001161 final boolean hasPermission = bundle.hasPermission( new ConfigurationPermission( location,
1162 ConfigurationPermission.TARGET ) );
1163 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2} (SecurityManager check)",
1164 new Object[]
1165 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1166 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001167 }
Felix Meschberger61207232011-11-17 10:06:45 +00001168
1169 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration={1} (no SecurityManager)",
1170 new Object[]
1171 { bundle.getLocation(), location } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001172 return true;
1173 }
1174 else
1175 {
1176 // single location, must match
Felix Meschberger61207232011-11-17 10:06:45 +00001177 final boolean hasPermission = location.equals( bundle.getLocation() );
1178 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2}", new Object[]
1179 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1180 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001181 }
1182 }
1183
Felix Meschberger61207232011-11-17 10:06:45 +00001184
Felix Meschberger007c50e2011-10-20 12:39:38 +00001185 // ---------- inner classes
1186
1187 private ServiceHelper createServiceHelper( ConfigurationImpl config )
1188 {
1189 if ( config.getFactoryPid() == null )
1190 {
1191 return new ManagedServiceHelper( config );
1192 }
1193 return new ManagedServiceFactoryHelper( config );
1194 }
1195
1196 private abstract class ServiceHelper
1197 {
1198 protected final ConfigurationImpl config;
1199
1200 private final Dictionary properties;
1201
1202 protected ServiceHelper( ConfigurationImpl config )
1203 {
1204 this.config = config;
1205 this.properties = config.getProperties( true );
1206 }
1207
1208 final ServiceReference[] getServices( )
1209 {
1210 try
1211 {
1212 ServiceReference[] refs = doGetServices();
1213 if ( refs != null && refs.length > 1 )
1214 {
1215 Arrays.sort( refs, RankingComparator.SRV_RANKING );
1216 }
1217 return refs;
1218 }
1219 catch ( InvalidSyntaxException ise )
1220 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001221 log( LogService.LOG_ERROR, "Service selection filter is invalid to update {0}", new Object[]
1222 { config, ise } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001223 }
1224 return null;
1225 }
1226
1227
1228 protected abstract ServiceReference[] doGetServices() throws InvalidSyntaxException;
1229
1230
1231 abstract void provide( ServiceReference service );
1232
1233
1234 abstract void remove( ServiceReference service );
1235
1236
1237 protected Dictionary getProperties( String targetPid, ServiceReference service )
1238 {
1239 Dictionary props = new CaseInsensitiveDictionary( this.properties );
1240 callPlugins( props, targetPid, service, config );
1241 return props;
1242 }
1243 }
1244
1245 private class ManagedServiceHelper extends ServiceHelper
1246 {
1247
1248 protected ManagedServiceHelper( ConfigurationImpl config )
1249 {
1250 super( config );
1251 }
1252
1253
1254 public ServiceReference[] doGetServices() throws InvalidSyntaxException
1255 {
1256 return bundleContext.getServiceReferences( ManagedService.class.getName(), "(" + Constants.SERVICE_PID
1257 + "=" + config.getPid() + ")" );
1258 }
1259
1260
1261 public void provide( ServiceReference service )
1262 {
1263 ManagedService srv = ( ManagedService ) bundleContext.getService( service );
1264 if ( srv != null )
1265 {
1266 try
1267 {
1268 Dictionary props = getProperties( this.config.getPid(), service );
1269 srv.updated( props );
1270 }
1271 catch ( Throwable t )
1272 {
1273 handleCallBackError( t, service, config );
1274 }
1275 finally
1276 {
1277 bundleContext.ungetService( service );
1278 }
1279 }
1280 }
1281
1282
1283 public void remove( ServiceReference service )
1284 {
1285 ManagedService srv = ( ManagedService ) bundleContext.getService( service );
1286 try
1287 {
1288 srv.updated( null );
1289 }
1290 catch ( Throwable t )
1291 {
1292 handleCallBackError( t, service, config );
1293 }
1294 finally
1295 {
1296 bundleContext.ungetService( service );
1297 }
1298 }
1299
1300 }
1301
1302 private class ManagedServiceFactoryHelper extends ServiceHelper
1303 {
1304
1305 protected ManagedServiceFactoryHelper( ConfigurationImpl config )
1306 {
1307 super( config );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001308 }
1309
1310
1311 public ServiceReference[] doGetServices() throws InvalidSyntaxException
1312 {
1313 return bundleContext.getServiceReferences( ManagedServiceFactory.class.getName(), "("
1314 + Constants.SERVICE_PID + "=" + config.getFactoryPid() + ")" );
1315 }
1316
1317
1318 public void provide( ServiceReference service )
1319 {
1320 ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext.getService( service );
1321 if ( srv != null )
1322 {
1323 try
1324 {
1325 Dictionary props = getProperties( this.config.getFactoryPid(), service );
1326 srv.updated( config.getPid(), props );
1327 }
1328 catch ( Throwable t )
1329 {
1330 handleCallBackError( t, service, config );
1331 }
1332 finally
1333 {
1334 bundleContext.ungetService( service );
1335 }
1336 }
1337 }
1338
1339
1340 public void remove( ServiceReference service )
1341 {
1342 ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext.getService( service );
1343 try
1344 {
1345 srv.deleted( config.getPid() );
1346 }
1347 catch ( Throwable t )
1348 {
1349 handleCallBackError( t, service, config );
1350 }
1351 finally
1352 {
1353 bundleContext.ungetService( service );
1354 }
1355 }
1356
1357 }
1358
1359 /**
1360 * The <code>ManagedServiceUpdate</code> updates a freshly registered
1361 * <code>ManagedService</code> with a specific configuration. If a
1362 * ManagedService is registered with multiple PIDs an instance of this
1363 * class is used for each registered PID.
1364 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001365 private class ManagedServiceUpdate implements Runnable
1366 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001367 private final String pid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001368
Felix Meschberger41cce522009-08-19 05:54:40 +00001369 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001370
Felix Meschberger41cce522009-08-19 05:54:40 +00001371 private final ManagedService service;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001372
Felix Meschberger41cce522009-08-19 05:54:40 +00001373 private final ConfigurationImpl config;
1374
1375 private final Dictionary rawProperties;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001376
Felix Meschberger61207232011-11-17 10:06:45 +00001377 private final long revision;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001378
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001379 ManagedServiceUpdate( String pid, ServiceReference sr, ManagedService service )
1380 {
1381 this.pid = pid;
1382 this.sr = sr;
1383 this.service = service;
Felix Meschberger41cce522009-08-19 05:54:40 +00001384
1385 // get or load configuration for the pid
1386 ConfigurationImpl config = null;
1387 Dictionary rawProperties = null;
Felix Meschberger61207232011-11-17 10:06:45 +00001388 long revision = -1;
Felix Meschberger41cce522009-08-19 05:54:40 +00001389 try
1390 {
Felix Meschbergerad949872011-11-16 10:34:54 +00001391 config = getConfiguration( pid );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001392 if ( config != null )
1393 {
1394 synchronized ( config )
1395 {
1396 rawProperties = config.getProperties( true );
Felix Meschberger61207232011-11-17 10:06:45 +00001397 revision = config.getRevision();
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001398 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001399 }
1400 }
1401 catch ( IOException ioe )
1402 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001403 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1404 { pid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001405 }
1406
1407 this.config = config;
1408 this.rawProperties = rawProperties;
Felix Meschberger61207232011-11-17 10:06:45 +00001409 this.revision = revision;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001410 }
1411
1412
1413 public void run()
1414 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001415 Dictionary properties = rawProperties;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001416
1417 // check configuration and call plugins if existing
Felix Meschberger41cce522009-08-19 05:54:40 +00001418 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001419 {
Felix Meschberger61207232011-11-17 10:06:45 +00001420 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1421 { pid, new Long( revision ) } );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001422
Felix Meschberger41243192009-01-14 19:59:58 +00001423 Bundle serviceBundle = sr.getBundle();
1424 if ( serviceBundle == null )
1425 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001426 log( LogService.LOG_INFO,
1427 "Service for PID {0} seems to already have been unregistered, not updating with configuration",
1428 new Object[]
1429 { pid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001430 return;
1431 }
1432
Felix Meschberger27689c12011-11-16 08:52:04 +00001433 if ( canReceive( serviceBundle, config.getBundleLocation() ) )
Felix Meschberger2941ef92007-08-20 13:15:16 +00001434 {
Felix Meschberger27689c12011-11-16 08:52:04 +00001435 // 104.4.2 Dynamic Binding
1436 config.tryBindLocation( serviceBundle.getLocation() );
1437
1438 // prepare the configuration for the service (call plugins)
1439 callPlugins( properties, pid, sr, config );
1440 }
1441 else
1442 {
1443 // CM 1.4 / 104.13.2.2 / 104.5.3
1444 // act as if there is no configuration
1445 log(
1446 LogService.LOG_DEBUG,
1447 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}; calling with null",
Felix Meschberger4f269292011-10-21 13:52:31 +00001448 new Object[]
1449 { pid, ConfigurationManager.toString( sr ), config.getBundleLocation() } );
Felix Meschberger27689c12011-11-16 08:52:04 +00001450
1451 // CM 1.4 / 104.5.3 ManagedService.updated must be
1452 // called with null if configuration is no visible
1453 properties = null;
Felix Meschberger2941ef92007-08-20 13:15:16 +00001454 }
1455
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001456 }
1457 else
1458 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001459 // 104.5.3 ManagedService.updated must be called with null
1460 // if no configuration is available
Felix Meschberger41cce522009-08-19 05:54:40 +00001461 properties = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001462 }
1463
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001464 // update the service with the configuration
1465 try
1466 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001467 service.updated( properties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001468 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001469 catch ( Throwable t )
1470 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001471 handleCallBackError( t, sr, config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001472 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001473 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001474
Felix Meschberger432e3872008-03-07 14:58:57 +00001475 public String toString()
1476 {
1477 return "ManagedService Update: pid=" + pid;
1478 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001479 }
1480
Felix Meschberger007c50e2011-10-20 12:39:38 +00001481 /**
1482 * The <code>ManagedServiceFactoryUpdate</code> updates a freshly
1483 * registered <code>ManagedServiceFactory</code> with a specific
1484 * configuration. If a ManagedServiceFactory is registered with
1485 * multiple PIDs an instance of this class is used for each registered
1486 * PID.
1487 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001488 private class ManagedServiceFactoryUpdate implements Runnable
1489 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001490 private final String factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001491
Felix Meschberger41cce522009-08-19 05:54:40 +00001492 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001493
Felix Meschberger41cce522009-08-19 05:54:40 +00001494 private final ManagedServiceFactory service;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001495
Felix Meschberger41cce522009-08-19 05:54:40 +00001496 private final Map configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001497
Felix Meschberger61207232011-11-17 10:06:45 +00001498 private final Map revisions;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001499
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001500 ManagedServiceFactoryUpdate( String factoryPid, ServiceReference sr, ManagedServiceFactory service )
1501 {
1502 this.factoryPid = factoryPid;
1503 this.sr = sr;
1504 this.service = service;
Felix Meschberger41cce522009-08-19 05:54:40 +00001505
1506 Factory factory = null;
1507 Map configs = null;
Felix Meschberger61207232011-11-17 10:06:45 +00001508 Map revisions = null;
Felix Meschberger41cce522009-08-19 05:54:40 +00001509 try
1510 {
1511 factory = getFactory( factoryPid );
1512 if (factory != null) {
1513 configs = new HashMap();
Felix Meschberger61207232011-11-17 10:06:45 +00001514 revisions = new HashMap();
Felix Meschberger41cce522009-08-19 05:54:40 +00001515 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
1516 {
1517 final String pid = ( String ) pi.next();
1518 ConfigurationImpl cfg;
1519 try
1520 {
Felix Meschbergerad949872011-11-16 10:34:54 +00001521 cfg = getConfiguration( pid );
Felix Meschberger41cce522009-08-19 05:54:40 +00001522 }
1523 catch ( IOException ioe )
1524 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001525 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1526 { pid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001527 continue;
1528 }
1529
1530 // sanity check on the configuration
1531 if ( cfg == null )
1532 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001533 log( LogService.LOG_ERROR, "Configuration {0} referred to by factory {1} does not exist",
1534 new Object[]
1535 { pid, factoryPid } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001536 factory.removePID( pid );
1537 factory.storeSilently();
1538 continue;
1539 }
1540 else if ( cfg.isNew() )
1541 {
1542 // Configuration has just been created but not yet updated
1543 // we currently just ignore it and have the update mechanism
1544 // provide the configuration to the ManagedServiceFactory
1545 // As of FELIX-612 (not storing new factory configurations)
1546 // this should not happen. We keep this for added stability
1547 // but raise the logging level to error.
Felix Meschberger4f269292011-10-21 13:52:31 +00001548 log( LogService.LOG_ERROR, "Ignoring new configuration pid={0}", new Object[]
1549 { pid } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001550 continue;
1551 }
1552 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1553 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001554 log( LogService.LOG_ERROR,
1555 "Configuration {0} referred to by factory {1} seems to belong to factory {2}",
1556 new Object[]
1557 { pid, factoryPid, cfg.getFactoryPid() } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001558 factory.removePID( pid );
1559 factory.storeSilently();
1560 continue;
1561 }
1562
1563 // get the configuration properties for later
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001564 synchronized ( cfg )
1565 {
1566 configs.put( cfg, cfg.getProperties( true ) );
Felix Meschberger61207232011-11-17 10:06:45 +00001567 revisions.put( cfg, new Long( cfg.getRevision() ) );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001568 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001569 }
1570 }
1571 }
1572 catch ( IOException ioe )
1573 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001574 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID {0}", new Object[]
1575 { factoryPid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001576 }
1577
Felix Meschberger41cce522009-08-19 05:54:40 +00001578 this.configs = configs;
Felix Meschberger61207232011-11-17 10:06:45 +00001579 this.revisions = revisions;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001580 }
1581
1582
1583 public void run()
1584 {
Felix Meschberger41243192009-01-14 19:59:58 +00001585 Bundle serviceBundle = sr.getBundle();
1586 if ( serviceBundle == null )
1587 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001588 log(
1589 LogService.LOG_INFO,
1590 "ManagedServiceFactory for factory PID {0} seems to already have been unregistered, not updating with factory",
1591 new Object[]
1592 { factoryPid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001593 return;
1594 }
1595
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001596 if ( configs == null || configs.isEmpty() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001597 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001598 log( LogService.LOG_DEBUG, "No configuration with factory PID {0}; not updating ManagedServiceFactory",
1599 new Object[]
1600 { factoryPid } );
1601 }
1602 else
1603 {
1604 for ( Iterator ci = configs.entrySet().iterator(); ci.hasNext(); )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001605 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001606 final Map.Entry entry = ( Map.Entry ) ci.next();
1607 final ConfigurationImpl cfg = ( ConfigurationImpl ) entry.getKey();
1608 final Dictionary properties = ( Dictionary ) entry.getValue();
1609 final long revision = ( ( Long ) revisions.get( cfg ) ).longValue();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001610
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001611 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1612 { cfg.getPid(), new Long( revision ) } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001613
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001614 // CM 1.4 / 104.13.2.1
1615 if ( !canReceive( serviceBundle, cfg.getBundleLocation() ) )
Felix Meschberger2941ef92007-08-20 13:15:16 +00001616 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001617 log( LogService.LOG_ERROR,
1618 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1619 new Object[]
1620 { cfg.getPid(), ConfigurationManager.toString( sr ), cfg.getBundleLocation() } );
1621 continue;
Felix Meschberger2941ef92007-08-20 13:15:16 +00001622 }
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001623
1624 // 104.4.2 Dynamic Binding
1625 cfg.tryBindLocation( serviceBundle.getLocation() );
1626
1627 // prepare the configuration for the service (call plugins)
1628 // call the plugins with cm.target set to the service's factory PID
1629 // (clarification in Section 104.9.1 of Compendium 4.2)
1630 callPlugins( properties, factoryPid, sr, cfg );
1631
1632 // update the service with the configuration (if non-null)
1633 if ( properties != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001634 {
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001635 log( LogService.LOG_DEBUG, "{0}: Updating configuration pid={1}", new Object[]
1636 { ConfigurationManager.toString( sr ), cfg.getPid() } );
1637
1638 try
1639 {
1640 service.updated( cfg.getPid(), properties );
1641 }
1642 catch ( Throwable t )
1643 {
1644 handleCallBackError( t, sr, cfg );
1645 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001646 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001647 }
1648 }
1649 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001650
1651
Felix Meschberger432e3872008-03-07 14:58:57 +00001652 public String toString()
1653 {
1654 return "ManagedServiceFactory Update: factoryPid=" + factoryPid;
1655 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001656 }
1657
Felix Meschberger007c50e2011-10-20 12:39:38 +00001658
1659 /**
1660 * The <code>UpdateConfiguration</code> is used to update
1661 * <code>ManagedService[Factory]</code> services with the configuration
1662 * they are subscribed to. This may cause the configuration to be
1663 * supplied to multiple services.
1664 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001665 private class UpdateConfiguration implements Runnable
1666 {
1667
Felix Meschberger41cce522009-08-19 05:54:40 +00001668 private final ConfigurationImpl config;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001669 private final ServiceHelper helper;
Felix Meschberger61207232011-11-17 10:06:45 +00001670 private final long revision;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001671
1672
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001673 UpdateConfiguration( final ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001674 {
1675 this.config = config;
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001676 synchronized ( config )
1677 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001678 this.helper = createServiceHelper( config );
Felix Meschberger61207232011-11-17 10:06:45 +00001679 this.revision = config.getRevision();
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001680 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001681 }
1682
1683
1684 public void run()
1685 {
Felix Meschberger61207232011-11-17 10:06:45 +00001686 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1687 { config.getPid(), new Long( revision ) } );
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001688
Felix Meschberger007c50e2011-10-20 12:39:38 +00001689 final ServiceReference[] srList = helper.getServices();
1690 if ( srList != null )
Felix Meschberger41cce522009-08-19 05:54:40 +00001691 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001692 // optionally bind dynamically to the first service
1693 config.tryBindLocation( srList[0].getBundle().getLocation() );
1694
1695 final String configBundleLocation = config.getBundleLocation();
1696
1697 // provide configuration to all services from the
1698 // correct bundle
Felix Meschberger41cce522009-08-19 05:54:40 +00001699 for ( int i = 0; i < srList.length; i++ )
1700 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001701 final ServiceReference ref = srList[i];
Felix Meschberger2444da62011-11-17 11:17:50 +00001702 final Bundle refBundle = ref.getBundle();
1703 if ( refBundle == null )
Felix Meschberger41cce522009-08-19 05:54:40 +00001704 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001705 log( LogService.LOG_DEBUG,
1706 "Service {0} seems to be unregistered concurrently (not providing configuration)",
1707 new Object[]
1708 { ConfigurationManager.toString( ref ) } );
1709 }
1710 else if ( canReceive( refBundle, configBundleLocation ) )
1711 {
1712 helper.provide( ref );
1713 }
1714 else
1715 {
1716 // CM 1.4 / 104.13.2.2
Felix Meschberger4f269292011-10-21 13:52:31 +00001717 log( LogService.LOG_ERROR,
1718 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1719 new Object[]
1720 { config.getPid(), ConfigurationManager.toString( ref ), configBundleLocation } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001721 }
1722
Felix Meschberger41cce522009-08-19 05:54:40 +00001723 }
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001724 }
Felix Meschberger137ee722011-11-16 09:51:59 +00001725 else if ( isLogEnabled( LogService.LOG_DEBUG ) )
1726 {
Felix Meschberger1ee888d2011-11-16 12:42:57 +00001727 log( LogService.LOG_DEBUG, "No ManagedService[Factory] registered for updates to configuration {0}",
Felix Meschberger137ee722011-11-16 09:51:59 +00001728 new Object[]
1729 { config.getPid() } );
1730 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001731 }
1732
1733
Felix Meschberger432e3872008-03-07 14:58:57 +00001734 public String toString()
1735 {
1736 return "Update: pid=" + config.getPid();
1737 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001738 }
1739
Felix Meschberger007c50e2011-10-20 12:39:38 +00001740
1741 /**
1742 * The <code>DeleteConfiguration</code> class is used to inform
1743 * <code>ManagedService[Factory]</code> services of a configuration
1744 * being deleted.
1745 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001746 private class DeleteConfiguration implements Runnable
1747 {
Felix Meschberger66423332007-08-22 08:46:34 +00001748
Felix Meschbergerce67d732009-08-20 06:26:35 +00001749 private final ConfigurationImpl config;
Felix Meschbergerc12db8c2009-08-19 06:43:59 +00001750 private final String configLocation;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001751
1752
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001753 DeleteConfiguration( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001754 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001755 /*
1756 * NOTE: We keep the configuration because it might be cleared just
1757 * after calling this method. The pid and factoryPid fields are
1758 * final and cannot be reset.
1759 */
1760 this.config = config;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001761 this.configLocation = config.getBundleLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001762 }
1763
1764
1765 public void run()
1766 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001767 final String pid = config.getPid();
1768 final String factoryPid = config.getFactoryPid();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001769 final ServiceHelper helper = createServiceHelper( config );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001770
Felix Meschberger007c50e2011-10-20 12:39:38 +00001771 ServiceReference[] srList = helper.getServices( );
1772 if ( srList != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001773 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001774 for ( int i = 0; i < srList.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001775 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001776 final ServiceReference sr = srList[i];
Felix Meschberger2444da62011-11-17 11:17:50 +00001777 final Bundle srBundle = sr.getBundle();
1778 if ( srBundle == null )
1779 {
1780 log( LogService.LOG_DEBUG,
1781 "Service {0} seems to be unregistered concurrently (not removing configuration)",
1782 new Object[]
1783 { ConfigurationManager.toString( sr ) } );
1784 }
1785 else if ( canReceive( srBundle, configLocation ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001786 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001787 helper.remove( sr );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001788 }
Felix Meschberger2444da62011-11-17 11:17:50 +00001789 else
1790 {
1791 // CM 1.4 / 104.13.2.2
1792 log( LogService.LOG_ERROR,
1793 "Cannot remove configuration {0} for {1}: No visibility to configuration bound to {2}",
1794 new Object[]
1795 { config.getPid(), ConfigurationManager.toString( sr ), configLocation } );
1796 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001797 }
1798 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001799
1800 if ( factoryPid != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001801 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001802 // remove the pid from the factory
1803 try
1804 {
1805 Factory factory = getFactory( factoryPid );
1806 factory.removePID( pid );
1807 factory.store();
1808 }
1809 catch ( IOException ioe )
1810 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001811 log( LogService.LOG_ERROR, "Failed removing {0} from the factory {1}", new Object[]
1812 { pid, factoryPid, ioe } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001813 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001814 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001815 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001816
Felix Meschberger432e3872008-03-07 14:58:57 +00001817 public String toString()
1818 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001819 return "Delete: pid=" + config.getPid();
Felix Meschberger432e3872008-03-07 14:58:57 +00001820 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001821 }
1822
Felix Meschberger007c50e2011-10-20 12:39:38 +00001823 private class LocationChanged implements Runnable
1824 {
1825 private final ConfigurationImpl config;
1826 private final String oldLocation;
1827
1828
1829 LocationChanged( ConfigurationImpl config, String oldLocation )
1830 {
1831 this.config = config;
1832 this.oldLocation = oldLocation;
1833 }
1834
1835
1836 public void run()
1837 {
1838 ServiceHelper helper = createServiceHelper( this.config );
1839 ServiceReference[] srList = helper.getServices( );
1840 if ( srList != null )
1841 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001842 for ( int i = 0; i < srList.length; i++ )
1843 {
1844 final ServiceReference sr = srList[i];
Felix Meschberger2444da62011-11-17 11:17:50 +00001845
1846 final Bundle srBundle = sr.getBundle();
1847 if ( srBundle == null )
1848 {
1849 log( LogService.LOG_DEBUG,
1850 "Service {0} seems to be unregistered concurrently (not processing)", new Object[]
1851 { ConfigurationManager.toString( sr ) } );
1852 continue;
1853 }
1854
1855 final boolean wasVisible = canReceive( srBundle, oldLocation );
1856 final boolean isVisible = canReceive( srBundle, config.getBundleLocation() );
1857
1858 // make sure the config is dynamically bound to the first
1859 // service if the config has been unbound causing this update
1860 if ( isVisible )
1861 {
1862 config.tryBindLocation( srBundle.getLocation() );
1863 }
1864
Felix Meschberger007c50e2011-10-20 12:39:38 +00001865 if ( wasVisible && !isVisible )
1866 {
1867 // call deleted method
1868 helper.remove( sr );
Felix Meschberger4f269292011-10-21 13:52:31 +00001869 log( LogService.LOG_DEBUG, "Configuration {0} revoked from {1} (no more visibility)",
1870 new Object[]
1871 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001872 }
1873 else if ( !wasVisible && isVisible )
1874 {
1875 // call updated method
1876 helper.provide( sr );
Felix Meschberger4f269292011-10-21 13:52:31 +00001877 log( LogService.LOG_DEBUG, "Configuration {0} provided to {1} (new visibility)", new Object[]
1878 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger35658d52011-10-20 21:43:58 +00001879 }
Felix Meschberger4f269292011-10-21 13:52:31 +00001880 else
Felix Meschberger35658d52011-10-20 21:43:58 +00001881 {
1882 // same visibility as before
Felix Meschberger4f269292011-10-21 13:52:31 +00001883 log( LogService.LOG_DEBUG, "Unmodified visibility to configuration {0} for {1}", new Object[]
1884 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001885 }
1886 }
1887 }
1888 }
1889
1890
1891 public String toString()
1892 {
1893 return "Location Changed (pid=" + config.getPid() + "): " + oldLocation + " ==> "
1894 + config.getBundleLocation();
1895 }
1896 }
1897
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001898 private class FireConfigurationEvent implements Runnable
1899 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001900 private final int type;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001901
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001902 private final String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001903
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001904 private final String factoryPid;
1905
1906 private final ServiceReference[] listenerReferences;
1907
1908 private final ConfigurationListener[] listeners;
1909
1910 private final Bundle[] listenerProvider;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001911
1912
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001913 private FireConfigurationEvent( final int type, final String pid, final String factoryPid)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001914 {
1915 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001916 this.pid = pid;
1917 this.factoryPid = factoryPid;
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001918
1919 final ServiceReference[] srs = configurationListenerTracker.getServiceReferences();
1920 if ( srs == null || srs.length == 0 )
1921 {
1922 this.listenerReferences = null;
1923 this.listeners = null;
1924 this.listenerProvider = null;
1925 }
1926 else
1927 {
1928 this.listenerReferences = srs;
1929 this.listeners = new ConfigurationListener[srs.length];
1930 this.listenerProvider = new Bundle[srs.length];
1931 for ( int i = 0; i < srs.length; i++ )
1932 {
1933 this.listeners[i] = ( ConfigurationListener ) configurationListenerTracker.getService( srs[i] );
1934 this.listenerProvider[i] = srs[i].getBundle();
1935 }
1936 }
1937 }
1938
1939
1940 boolean hasConfigurationEventListeners()
1941 {
1942 return this.listenerReferences != null;
1943 }
1944
1945
1946 String getTypeName()
1947 {
1948 switch ( type )
1949 {
1950 case ConfigurationEvent.CM_DELETED:
1951 return "CM_DELETED";
1952 case ConfigurationEvent.CM_UPDATED:
1953 return "CM_UPDATED";
Felix Meschberger007c50e2011-10-20 12:39:38 +00001954 case ConfigurationEvent.CM_LOCATION_CHANGED:
1955 return "CM_LOCATION_CHANGED";
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001956 default:
1957 return "<UNKNOWN(" + type + ")>";
1958 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001959 }
1960
1961
1962 public void run()
1963 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001964 final String typeName = getTypeName();
1965 final ConfigurationEvent event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001966
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001967 for ( int i = 0; i < listeners.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001968 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001969 if ( listenerProvider[i].getState() == Bundle.ACTIVE )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001970 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001971 log( LogService.LOG_DEBUG, "Sending {0} event for {1} to {2}", new Object[]
1972 { typeName, pid, ConfigurationManager.toString( listenerReferences[i] ) } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001973
1974 try
1975 {
1976 listeners[i].configurationEvent( event );
1977 }
1978 catch ( Throwable t )
1979 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001980 log( LogService.LOG_ERROR, "Unexpected problem delivering configuration event to {0}",
1981 new Object[]
1982 { ConfigurationManager.toString( listenerReferences[i] ), t } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001983 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001984 }
1985 }
1986 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001987
Felix Meschberger432e3872008-03-07 14:58:57 +00001988 public String toString()
1989 {
1990 return "Fire ConfigurationEvent: pid=" + pid;
1991 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001992 }
1993
Felix Meschberger41cce522009-08-19 05:54:40 +00001994 private static class ManagedServiceTracker extends ServiceTracker
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001995 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001996
Felix Meschberger41cce522009-08-19 05:54:40 +00001997 private final ConfigurationManager cm;
1998
1999
2000 ManagedServiceTracker( ConfigurationManager cm )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002001 {
Felix Meschberger41cce522009-08-19 05:54:40 +00002002 super( cm.bundleContext, ManagedService.class.getName(), null );
Carsten Ziegeler41683982007-12-27 08:35:27 +00002003 this.cm = cm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002004 open();
2005 }
2006
2007
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002008 public Object addingService( ServiceReference reference )
2009 {
Felix Meschberger05d89e12011-11-03 23:37:10 +00002010 Object service = super.addingService( reference );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002011
2012 // configure the managed service
Felix Meschberger05d89e12011-11-03 23:37:10 +00002013 final String[] pids;
2014 if ( service instanceof ManagedService )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002015 {
Felix Meschberger05d89e12011-11-03 23:37:10 +00002016 pids = getServicePid( reference );
2017 cm.configure( pids, reference, ( ManagedService ) service );
Felix Meschberger2fd5b582007-12-10 10:32:29 +00002018 }
2019 else
2020 {
Felix Meschberger4f269292011-10-21 13:52:31 +00002021 cm.log( LogService.LOG_WARNING, "Service {0} is not a ManagedService", new Object[]
Felix Meschberger05d89e12011-11-03 23:37:10 +00002022 { service } );
2023 pids = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002024 }
2025
Felix Meschberger05d89e12011-11-03 23:37:10 +00002026 return new ManagedServiceHolder( service, pids );
2027 }
2028
2029
2030 public void modifiedService( ServiceReference reference, Object service )
2031 {
2032 ManagedServiceHolder holder = ( ManagedServiceHolder ) service;
2033 String[] pids = getServicePid( reference );
2034
2035 if ( holder.isDifferentPids( pids ) )
2036 {
2037 cm.configure( pids, reference, ( ManagedService ) holder.getManagedService() );
2038 holder.setConfiguredPids( pids );
2039 }
2040 }
2041
2042
2043 public void removedService( ServiceReference reference, Object service )
2044 {
2045 final Object serviceObject = ( ( ManagedServiceHolder ) service ).getManagedService();
2046 super.removedService( reference, serviceObject );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002047 }
2048 }
2049
Felix Meschberger41cce522009-08-19 05:54:40 +00002050 private static class ManagedServiceFactoryTracker extends ServiceTracker
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002051 {
Felix Meschberger41cce522009-08-19 05:54:40 +00002052 private final ConfigurationManager cm;
2053
2054
2055 ManagedServiceFactoryTracker( ConfigurationManager cm )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002056 {
Felix Meschberger41cce522009-08-19 05:54:40 +00002057 super( cm.bundleContext, ManagedServiceFactory.class.getName(), null );
2058 this.cm = cm;
2059 open();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002060 }
2061
2062
2063 public Object addingService( ServiceReference reference )
2064 {
Felix Meschberger2fd5b582007-12-10 10:32:29 +00002065 Object serviceObject = super.addingService( reference );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002066
Felix Meschberger2fd5b582007-12-10 10:32:29 +00002067 // configure the managed service factory
Felix Meschberger05d89e12011-11-03 23:37:10 +00002068 final String[] pids;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00002069 if ( serviceObject instanceof ManagedServiceFactory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002070 {
Felix Meschberger05d89e12011-11-03 23:37:10 +00002071 pids = getServicePid( reference );
2072 cm.configure( pids, reference, ( ManagedServiceFactory ) serviceObject );
Felix Meschberger2fd5b582007-12-10 10:32:29 +00002073 }
2074 else
2075 {
Felix Meschberger4f269292011-10-21 13:52:31 +00002076 cm.log( LogService.LOG_WARNING, "Service {0} is not a ManagedServiceFactory", new Object[]
2077 { serviceObject } );
Felix Meschberger05d89e12011-11-03 23:37:10 +00002078 pids = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002079 }
2080
Felix Meschberger05d89e12011-11-03 23:37:10 +00002081 return new ManagedServiceHolder( serviceObject, pids );
2082 }
2083
2084
2085 public void modifiedService( ServiceReference reference, Object service )
2086 {
2087 ManagedServiceHolder holder = ( ManagedServiceHolder ) service;
2088 String[] pids = getServicePid( reference );
2089
2090 if ( holder.isDifferentPids( pids ) )
2091 {
2092 cm.configure( pids, reference, ( ManagedServiceFactory ) holder.getManagedService() );
2093 holder.setConfiguredPids( pids );
2094 }
2095
2096 super.modifiedService( reference, service );
2097 }
2098
2099
2100 public void removedService( ServiceReference reference, Object service )
2101 {
2102 final Object serviceObject = ( ( ManagedServiceHolder ) service ).getManagedService();
2103 super.removedService( reference, serviceObject );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002104 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002105 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00002106
Felix Meschberger05d89e12011-11-03 23:37:10 +00002107 private static class ManagedServiceHolder
2108 {
2109 private final Object managedService;
2110 private String[] configuredPids;
Felix Meschberger007c50e2011-10-20 12:39:38 +00002111
Felix Meschberger05d89e12011-11-03 23:37:10 +00002112
2113 ManagedServiceHolder( final Object managedService, final String[] configuredPids )
2114 {
2115 this.managedService = managedService;
2116 this.configuredPids = configuredPids;
2117 }
2118
2119
2120 public Object getManagedService()
2121 {
2122 return managedService;
2123 }
2124
2125
2126 public void setConfiguredPids( String[] configuredPids )
2127 {
2128 this.configuredPids = configuredPids;
2129 }
2130
2131
2132 boolean isDifferentPids( final String[] pids )
2133 {
2134 if ( this.configuredPids == null && pids == null )
2135 {
2136 return false;
2137 }
2138 else if ( this.configuredPids == null )
2139 {
2140 return true;
2141 }
2142 else if ( pids == null )
2143 {
2144 return true;
2145 }
2146 else if ( this.configuredPids.length != pids.length )
2147 {
2148 return true;
2149 }
2150 else
2151 {
2152 HashSet thisPids = new HashSet( Arrays.asList( this.configuredPids ) );
2153 HashSet otherPids = new HashSet( Arrays.asList( pids ) );
2154 return !thisPids.equals( otherPids );
2155 }
2156 }
2157 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002158}