blob: 60d216e470bbe375fe7d3eb4a270a9bda9926cc3 [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
164 public void start( BundleContext bundleContext )
165 {
166 // track the log service using a ServiceTracker
Felix Meschberger85b355d2007-08-31 07:17:38 +0000167 logTracker = new ServiceTracker( bundleContext, LOG_SERVICE_NAME , null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000168 logTracker.open();
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000169
Felix Meschberger08282c32009-01-28 07:01:55 +0000170 // assign the log level
171 String logLevelProp = bundleContext.getProperty( CM_LOG_LEVEL );
172 if ( logLevelProp == null )
173 {
174 logLevel = CM_LOG_LEVEL_DEFAULT;
175 }
176 else
177 {
178 try
179 {
180 logLevel = Integer.parseInt( logLevelProp );
181 }
182 catch ( NumberFormatException nfe )
183 {
184 logLevel = CM_LOG_LEVEL_DEFAULT;
185 }
186 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000187
188 // set up some fields
189 this.bundleContext = bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000190
191 // configurationlistener support
192 configurationListenerTracker = new ServiceTracker( bundleContext, ConfigurationListener.class.getName(), null );
193 configurationListenerTracker.open();
194
195 // initialize the asynchonous updater thread
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000196 ThreadGroup tg = new ThreadGroup( "Configuration Admin Service" );
197 tg.setDaemon( true );
198 this.updateThread = new UpdateThread( this, tg, "CM Configuration Updater" );
199 this.eventThread = new UpdateThread( this, tg, "CM Event Dispatcher" );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000200
201 // set up the location (might throw IllegalArgumentException)
202 try
203 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000204 FilePersistenceManager fpm = new FilePersistenceManager( bundleContext, bundleContext
205 .getProperty( CM_CONFIG_DIR ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000206 Hashtable props = new Hashtable();
207 props.put( Constants.SERVICE_PID, fpm.getClass().getName() );
208 props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
209 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
210 props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
211 bundleContext.registerService( PersistenceManager.class.getName(), fpm, props );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000212
213 // setup dynamic configuration bindings
214 dynamicBindings = new DynamicBindings( bundleContext, fpm );
215 }
216 catch ( IOException ioe )
217 {
218 log( LogService.LOG_ERROR, "Failure setting up dynamic configuration bindings", ioe );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000219 }
220 catch ( IllegalArgumentException iae )
221 {
222 log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
223 }
224
225 // register as bundle and service listener
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000226 handleBundleEvents = true;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000227 bundleContext.addBundleListener( this );
228
229 // get all persistence managers to begin with
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000230 pmtCount = 1; // make sure to get the persistence managers at least once
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000231 persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
232 persistenceManagerTracker.open();
233
234 // create and register configuration admin - start after PM tracker ...
235 ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
236 Hashtable props = new Hashtable();
237 props.put( Constants.SERVICE_PID, "org.apache.felix.cm.ConfigurationAdmin" );
238 props.put( Constants.SERVICE_DESCRIPTION, "Configuration Admin Service Specification 1.2 Implementation" );
239 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000240 configurationAdminRegistration = bundleContext.registerService( ConfigurationAdmin.class.getName(), caf, props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000241
Felix Meschberger4b26df92011-02-01 12:41:45 +0000242 // start processing the event queues only after registering the service
243 // see FELIX-2813 for details
244 this.updateThread.start();
245 this.eventThread.start();
246
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000247 // start handling ManagedService[Factory] services
Carsten Ziegeler41683982007-12-27 08:35:27 +0000248 managedServiceTracker = new ManagedServiceTracker(this);
249 managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this);
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000250 }
251
252
253 public void stop( BundleContext bundleContext )
254 {
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000255
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000256 // stop handling bundle events immediately
257 handleBundleEvents = false;
258
Felix Meschberger4b26df92011-02-01 12:41:45 +0000259 // stop queue processing before unregistering the service
260 // see FELIX-2813 for details
261 if ( updateThread != null )
262 {
263 updateThread.terminate();
264 }
265 if ( eventThread != null )
266 {
267 eventThread.terminate();
268 }
269
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000270 // immediately unregister the Configuration Admin before cleaning up
Felix Meschberger10568352009-01-15 08:57:11 +0000271 // clearing the field before actually unregistering the service
272 // prevents IllegalStateException in getServiceReference() if
273 // the field is not null but the service already unregistered
274 if (configurationAdminRegistration != null) {
275 ServiceRegistration reg = configurationAdminRegistration;
276 configurationAdminRegistration = null;
277 reg.unregister();
278 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000279
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000280 // stop handling ManagedService[Factory] services
281 managedServiceFactoryTracker.close();
282 managedServiceTracker.close();
283
284 // don't care for PersistenceManagers any more
285 persistenceManagerTracker.close();
286
287 // stop listening for events
288 bundleContext.removeBundleListener( this );
289
290 if ( configurationListenerTracker != null )
291 {
292 configurationListenerTracker.close();
293 }
294
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000295 if ( logTracker != null )
296 {
297 logTracker.close();
298 }
299
Felix Meschberger6a698df2009-08-16 18:38:46 +0000300 // just ensure the configuration cache is empty
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000301 synchronized ( configurations )
302 {
303 configurations.clear();
304 }
305
Felix Meschberger6a698df2009-08-16 18:38:46 +0000306 // just ensure the factory cache is empty
307 synchronized ( factories )
308 {
309 factories.clear();
310 }
311
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000312 this.bundleContext = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000313 }
314
315
316 // ---------- Configuration caching support --------------------------------
317
318 ConfigurationImpl getCachedConfiguration( String pid )
319 {
320 synchronized ( configurations )
321 {
322 return ( ConfigurationImpl ) configurations.get( pid );
323 }
324 }
325
326
Felix Meschberger6a698df2009-08-16 18:38:46 +0000327 ConfigurationImpl[] getCachedConfigurations()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000328 {
329 synchronized ( configurations )
330 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000331 return ( ConfigurationImpl[] ) configurations.values().toArray(
332 new ConfigurationImpl[configurations.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000333 }
334 }
335
336
Felix Meschberger2941ef92007-08-20 13:15:16 +0000337 ConfigurationImpl cacheConfiguration( ConfigurationImpl configuration )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000338 {
339 synchronized ( configurations )
340 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000341 Object existing = configurations.get( configuration.getPid() );
342 if ( existing != null )
343 {
344 return ( ConfigurationImpl ) existing;
345 }
346
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000347 configurations.put( configuration.getPid(), configuration );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000348 return configuration;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000349 }
350 }
351
352
353 void removeConfiguration( ConfigurationImpl configuration )
354 {
355 synchronized ( configurations )
356 {
357 configurations.remove( configuration.getPid() );
358 }
359 }
360
361
Felix Meschberger6a698df2009-08-16 18:38:46 +0000362 Factory getCachedFactory( String factoryPid )
363 {
364 synchronized ( factories )
365 {
366 return ( Factory ) factories.get( factoryPid );
367 }
368 }
369
370
371 Factory[] getCachedFactories()
372 {
373 synchronized ( factories )
374 {
375 return ( Factory[] ) factories.values().toArray( new Factory[factories.size()] );
376 }
377 }
378
379
380 void cacheFactory( Factory factory )
381 {
382 synchronized ( factories )
383 {
384 factories.put( factory.getFactoryPid(), factory );
385 }
386 }
387
388
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000389 // ---------- ConfigurationAdminImpl support
Felix Meschberger6a698df2009-08-16 18:38:46 +0000390
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000391 void setDynamicBundleLocation( final String pid, final String location )
392 {
393 if ( dynamicBindings != null )
394 {
395 try
396 {
397 dynamicBindings.putLocation( pid, location );
398 }
399 catch ( IOException ioe )
400 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000401 log( LogService.LOG_ERROR, "Failed storing dynamic configuration binding for {0} to {1}", new Object[]
402 { pid, location, ioe } );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000403 }
404 }
405 }
406
407
408 String getDynamicBundleLocation( final String pid )
409 {
410 if ( dynamicBindings != null )
411 {
412 return dynamicBindings.getLocation( pid );
413 }
414
415 return null;
416 }
417
418
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000419 ConfigurationImpl createFactoryConfiguration( ConfigurationAdminImpl configurationAdmin, String factoryPid )
420 throws IOException
421 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000422 return createFactoryConfiguration( factoryPid, configurationAdmin.getBundle().getLocation() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000423 }
424
425
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000426 ConfigurationImpl createFactoryConfiguration( String factoryPid, String location ) throws IOException
427 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000428 return createConfiguration( createPid( factoryPid ), factoryPid, location );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000429 }
430
431
Felix Meschberger2941ef92007-08-20 13:15:16 +0000432 ConfigurationImpl getExistingConfiguration( String pid ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000433 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000434 ConfigurationImpl config = getCachedConfiguration( pid );
435 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000436 {
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000437 log( LogService.LOG_DEBUG, "Found cached configuration {0} bound to {1}", new Object[]
438 { pid, config.getBundleLocation() } );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000439 return config;
440 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000441
Felix Meschberger2941ef92007-08-20 13:15:16 +0000442 PersistenceManager[] pmList = getPersistenceManagers();
443 for ( int i = 0; i < pmList.length; i++ )
444 {
445 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000446 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000447 Dictionary props = pmList[i].load( pid );
448 config = new ConfigurationImpl( this, pmList[i], props );
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000449 log( LogService.LOG_DEBUG, "Found existing configuration {0} bound to {1}", new Object[]
450 { pid, config.getBundleLocation() } );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000451 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000452 }
453 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000454
Felix Meschberger2941ef92007-08-20 13:15:16 +0000455 // neither the cache nor any persistence manager has configuration
456 return null;
457 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000458
459
Felix Meschberger2941ef92007-08-20 13:15:16 +0000460 ConfigurationImpl getConfiguration( String pid, String bundleLocation ) throws IOException
461 {
462 // check for existing (cached or persistent) configuration
463 ConfigurationImpl config = getExistingConfiguration( pid );
464 if ( config != null )
465 {
466 return config;
467 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000468
Felix Meschberger2941ef92007-08-20 13:15:16 +0000469 // else create new configuration also setting the bundle location
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000470 // and cache the new configuration
471 config = createConfiguration( pid, null, bundleLocation );
472 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000473 }
474
475
476 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
477 throws IOException, InvalidSyntaxException
478 {
479 Filter filter = null;
480 if ( filterString != null )
481 {
482 filter = bundleContext.createFilter( filterString );
483 }
484
Felix Meschberger4f269292011-10-21 13:52:31 +0000485 log( LogService.LOG_DEBUG, "Listing configurations matching {0}", new Object[]
486 { filterString } );
487
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000488 List configList = new ArrayList();
489
490 PersistenceManager[] pmList = getPersistenceManagers();
491 for ( int i = 0; i < pmList.length; i++ )
492 {
493 Enumeration configs = pmList[i].getDictionaries();
494 while ( configs.hasMoreElements() )
495 {
496 Dictionary config = ( Dictionary ) configs.nextElement();
497
498 // ignore non-Configuration dictionaries
Felix Meschberger86a0d172007-07-04 07:15:01 +0000499 String pid = ( String ) config.get( Constants.SERVICE_PID );
500 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000501 {
502 continue;
503 }
504
Felix Meschberger007c50e2011-10-20 12:39:38 +0000505 // CM 1.4 / 104.13.2.3 Permission required
506 if ( !configurationAdmin.hasPermission( ( String ) config
507 .get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000508 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000509 log(
510 LogService.LOG_DEBUG,
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000511 "Omitting configuration {0}: No permission for bundle {1} on configuration bound to {2}",
Felix Meschberger4f269292011-10-21 13:52:31 +0000512 new Object[]
513 { config.get( Constants.SERVICE_PID ), configurationAdmin.getBundle().getLocation(),
514 config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000515 continue;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000516 }
517
518 // check filter
519 if ( filter == null || filter.match( config ) )
520 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000521 // ensure the service.pid and returned a cached config if available
522 ConfigurationImpl cfg = getCachedConfiguration( pid );
523 if ( cfg == null )
524 {
525 cfg = new ConfigurationImpl( this, pmList[i], config );
526 }
527
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000528 // FELIX-611: Ignore configuration objects without props
529 if ( !cfg.isNew() )
530 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000531 log( LogService.LOG_DEBUG, "Adding configuration {0}", new Object[]
532 { config.get( Constants.SERVICE_PID ) } );
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000533 configList.add( cfg );
534 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000535 else
536 {
537 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Is new", new Object[]
538 { config.get( Constants.SERVICE_PID ) } );
539 }
540 } else {
541 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Does not match filter", new Object[]
542 { config.get( Constants.SERVICE_PID ) } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000543 }
544 }
545 }
546
Felix Meschberger8faceff2007-07-04 07:19:48 +0000547 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000548 .size()] );
549 }
550
551
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000552 void deleted( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000553 {
554 // remove the configuration from the cache
555 removeConfiguration( config );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000556 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, config.getPid(), config.getFactoryPid() );
557 updateThread.schedule( new DeleteConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000558 log( LogService.LOG_DEBUG, "DeleteConfiguration({0}) scheduled", new Object[]
559 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000560 }
561
562
Felix Meschbergerce67d732009-08-20 06:26:35 +0000563 void updated( ConfigurationImpl config, boolean fireEvent )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000564 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000565 if ( fireEvent )
566 {
567 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPid(), config.getFactoryPid() );
568 }
569 updateThread.schedule( new UpdateConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000570 log( LogService.LOG_DEBUG, "UpdateConfiguration({0}) scheduled", new Object[]
571 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000572 }
573
574
Felix Meschberger007c50e2011-10-20 12:39:38 +0000575 void locationChanged( ConfigurationImpl config, String oldLocation )
576 {
577 fireConfigurationEvent( ConfigurationEvent.CM_LOCATION_CHANGED, config.getPid(), config.getFactoryPid() );
Felix Meschberger35658d52011-10-20 21:43:58 +0000578 if ( oldLocation != null && !config.isNew() )
Felix Meschberger007c50e2011-10-20 12:39:38 +0000579 {
580 updateThread.schedule( new LocationChanged( config, oldLocation ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000581 log( LogService.LOG_DEBUG, "LocationChanged({0}, {1}=>{2}) scheduled", new Object[]
582 { config.getPid(), oldLocation, config.getBundleLocation() } );
Felix Meschberger35658d52011-10-20 21:43:58 +0000583 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000584 else
Felix Meschberger35658d52011-10-20 21:43:58 +0000585 {
586 log( LogService.LOG_DEBUG,
Felix Meschberger4f269292011-10-21 13:52:31 +0000587 "LocationChanged not scheduled for {0} (old location is null or configuration is new)", new Object[]
588 { config.getPid() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000589 }
590 }
591
592
Felix Meschberger66423332007-08-22 08:46:34 +0000593 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000594 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000595 FireConfigurationEvent event = new FireConfigurationEvent( type, pid, factoryPid );
596 if ( event.hasConfigurationEventListeners() )
597 {
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000598 eventThread.schedule( event );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000599 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000600 else
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000601 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000602 log( LogService.LOG_DEBUG, "No ConfigurationListeners to send {0} event to.", new Object[]
603 { event.getTypeName() } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000604 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000605 }
606
607
608 // ---------- BundleListener -----------------------------------------------
609
610 public void bundleChanged( BundleEvent event )
611 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000612 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000613 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000614 final String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000615
Felix Meschberger6a698df2009-08-16 18:38:46 +0000616 // we only reset dynamic bindings, which are only present in
617 // cached configurations, hence only consider cached configs here
618 final ConfigurationImpl[] configs = getCachedConfigurations();
619 for ( int i = 0; i < configs.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000620 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000621 final ConfigurationImpl cfg = configs[i];
Felix Meschberger41cce522009-08-19 05:54:40 +0000622 if ( location.equals( cfg.getDynamicBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000623 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000624 cfg.setDynamicBundleLocation( null, true );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000625 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000626 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000627 }
628 }
629
630
631 // ---------- internal -----------------------------------------------------
632
633 private PersistenceManager[] getPersistenceManagers()
634 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000635 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
636 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000637 {
638
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000639 List pmList = new ArrayList();
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000640 PersistenceManager[] pm;
641
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000642 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
643 if ( refs == null || refs.length == 0 )
644 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000645 pm = new PersistenceManager[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000646 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000647 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000648 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000649 // sort the references according to the cmRanking property
Felix Meschberger007c50e2011-10-20 12:39:38 +0000650 if ( refs.length > 1 )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000651 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000652 Arrays.sort( refs, RankingComparator.SRV_RANKING );
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000653 }
654
655 // create the service array from the sorted set of referenecs
Felix Meschberger007c50e2011-10-20 12:39:38 +0000656 for ( int i = 0; i < refs.length; i++ )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000657 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000658 Object service = persistenceManagerTracker.getService( refs[i] );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000659 if ( service != null )
660 {
Felix Meschbergera86cdfc2010-08-25 09:32:36 +0000661 pmList.add( new CachingPersistenceManagerProxy( ( PersistenceManager ) service ) );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000662 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000663 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000664
665 pm = ( PersistenceManager[] ) pmList.toArray( new PersistenceManager[pmList.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000666 }
667
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000668 pmtCount = pm.length;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000669 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000670 }
671
672 return persistenceManagers;
673 }
674
675
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000676 private ServiceReference getServiceReference()
677 {
678 ServiceRegistration reg = configurationAdminRegistration;
679 return ( reg != null ) ? reg.getReference() : null;
680 }
681
682
Felix Meschberger05d89e12011-11-03 23:37:10 +0000683 /**
684 * Configures the ManagedService and returns the service.pid
685 * service property as a String[], which may be <code>null</code> if
686 * the ManagedService does not have such a property.
687 */
688 private void configure( String[] pids, ServiceReference sr, ManagedService service )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000689 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000690 if ( pids != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000691 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000692 for ( int i = 0; i < pids.length; i++ )
693 {
694 ManagedServiceUpdate update = new ManagedServiceUpdate( pids[i], sr, service );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000695 updateThread.schedule( update );
Felix Meschberger4f269292011-10-21 13:52:31 +0000696 log( LogService.LOG_DEBUG, "ManagedServiceUpdate({0}) scheduled", new Object[]
697 { pids[i] } );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000698 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000699 }
Felix Meschberger851c6412009-08-16 18:43:26 +0000700 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000701
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000702
Felix Meschberger05d89e12011-11-03 23:37:10 +0000703 /**
704 * Configures the ManagedServiceFactory and returns the service.pid
705 * service property as a String[], which may be <code>null</code> if
706 * the ManagedServiceFactory does not have such a property.
707 */
708 private void configure( String[] pids, ServiceReference sr, ManagedServiceFactory service )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000709 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000710 if ( pids != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000711 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000712 for ( int i = 0; i < pids.length; i++ )
713 {
714 ManagedServiceFactoryUpdate update = new ManagedServiceFactoryUpdate( pids[i], sr, service );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000715 updateThread.schedule( update );
Felix Meschberger4f269292011-10-21 13:52:31 +0000716 log( LogService.LOG_DEBUG, "ManagedServiceFactoryUpdate({0}) scheduled", new Object[]
717 { pids[i] } );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000718 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000719 }
Felix Meschberger851c6412009-08-16 18:43:26 +0000720 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000721
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000722
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000723 /**
724 * Factory method to create a new configuration object. The configuration
725 * object returned is not stored in configuration cache and only persisted
726 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000727 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000728 * @param pid
729 * The PID of the new configuration object. Must not be
730 * <code>null</code>.
731 * @param factoryPid
732 * The factory PID of the new configuration. Not
Felix Meschberger6a698df2009-08-16 18:38:46 +0000733 * <code>null</code> if the new configuration object belongs to a
734 * factory. The configuration object will not be persisted if
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000735 * this parameter is not <code>null</code>.
736 * @param bundleLocation
737 * The bundle location of the bundle to which the configuration
Felix Meschberger6a698df2009-08-16 18:38:46 +0000738 * belongs or <code>null</code> if the configuration is not bound
739 * yet.
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000740 * @return The new configuration object
741 * @throws IOException
742 * May be thrown if an error occurrs persisting the new
743 * configuration object.
744 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000745 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000746 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000747 log( LogService.LOG_DEBUG, "createConfiguration({0}, {1}, {2})", new Object[]
748 { pid, factoryPid, bundleLocation } );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000749 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000750 }
751
752
753 Factory getFactory( String factoryPid ) throws IOException
754 {
Felix Meschbergerf4631322008-03-10 12:32:35 +0000755 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000756 if ( factory != null )
757 {
758 return factory;
759 }
760
761 PersistenceManager[] pmList = getPersistenceManagers();
762 for ( int i = 0; i < pmList.length; i++ )
763 {
764 if ( Factory.exists( pmList[i], factoryPid ) )
765 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000766 factory = Factory.load( this, pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000767 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000768 return factory;
769 }
770 }
771
772 // if getting here, there is no configuration yet, optionally create new
773 return createFactory( factoryPid );
774 }
775
776
777 Factory createFactory( String factoryPid )
778 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000779 Factory factory = new Factory( this, getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000780 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000781 return factory;
782 }
783
784
Felix Meschberger2941ef92007-08-20 13:15:16 +0000785 /**
786 * Calls the registered configuration plugins on the given configuration
Felix Meschberger41cce522009-08-19 05:54:40 +0000787 * properties from the given configuration object unless the configuration
788 * has just been created and not been updated yet.
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000789 *
Felix Meschberger41cce522009-08-19 05:54:40 +0000790 * @param props The configuraiton properties run through the registered
791 * ConfigurationPlugin services. This may be <code>null</code>
792 * in which case this method just immediately returns.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000793 * @param targetPid The identification of the configuration update used to
794 * select the plugins according to their cm.target service
795 * property
Felix Meschberger2941ef92007-08-20 13:15:16 +0000796 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000797 * is to be updated with configuration
Felix Meschberger2941ef92007-08-20 13:15:16 +0000798 * @param cfg The configuration object whose properties have to be passed
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000799 * through the plugins
Felix Meschberger2941ef92007-08-20 13:15:16 +0000800 */
Felix Meschberger41cce522009-08-19 05:54:40 +0000801 private void callPlugins( final Dictionary props, final String targetPid, final ServiceReference sr,
802 final ConfigurationImpl cfg )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000803 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000804 // guard against NPE for new configuration never updated
805 if (props == null) {
Felix Meschberger41cce522009-08-19 05:54:40 +0000806 return;
Felix Meschberger2941ef92007-08-20 13:15:16 +0000807 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000808
809 ServiceReference[] plugins = null;
810 try
811 {
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000812 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000813 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000814 }
815 catch ( InvalidSyntaxException ise )
816 {
817 // no filter, no exception ...
818 }
819
820 // abort early if there are no plugins
821 if ( plugins == null || plugins.length == 0 )
822 {
Felix Meschberger41cce522009-08-19 05:54:40 +0000823 return;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000824 }
825
826 // sort the plugins by their service.cmRanking
Felix Meschberger007c50e2011-10-20 12:39:38 +0000827 if ( plugins.length > 1 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000828 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000829 Arrays.sort( plugins, RankingComparator.CM_RANKING );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000830 }
831
832 // call the plugins in order
Felix Meschberger007c50e2011-10-20 12:39:38 +0000833 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000834 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000835 ServiceReference pluginRef = plugins[i];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000836 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000837 if ( plugin != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000838 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000839 try
840 {
841 plugin.modifyConfiguration( sr, props );
842 }
843 catch ( Throwable t )
844 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000845 log( LogService.LOG_ERROR, "Unexpected problem calling configuration plugin {0}", new Object[]
846 { toString( pluginRef ), t } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000847 }
848 finally
849 {
850 // ensure ungetting the plugin
851 bundleContext.ungetService( pluginRef );
852 }
853 cfg.setAutoProperties( props, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000854 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000855 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000856 }
857
858
859 /**
860 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000861 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000862 * @param factoryPid
863 * @return
864 */
865 private static String createPid( String factoryPid )
866 {
Felix Meschberger417f66c2011-02-04 11:25:23 +0000867 Random ng = numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000868 if ( ng == null )
869 {
Felix Meschberger417f66c2011-02-04 11:25:23 +0000870 // FELIX-2771 Secure Random not available on Mika
871 try
872 {
873 ng = new SecureRandom();
874 }
875 catch ( Throwable t )
876 {
877 // fall back to Random
878 ng = new Random();
879 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000880 }
881
882 byte[] randomBytes = new byte[16];
883 ng.nextBytes( randomBytes );
884 randomBytes[6] &= 0x0f; /* clear version */
885 randomBytes[6] |= 0x40; /* set to version 4 */
886 randomBytes[8] &= 0x3f; /* clear variant */
887 randomBytes[8] |= 0x80; /* set to IETF variant */
888
889 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
890
891 // prefix the new pid with the factory pid
892 buf.append( factoryPid ).append( "." );
893
894 // serialize the UUID into the buffer
895 for ( int i = 0; i < randomBytes.length; i++ )
896 {
897
898 if ( i == 4 || i == 6 || i == 8 || i == 10 )
899 {
900 buf.append( '-' );
901 }
902
903 int val = randomBytes[i] & 0xff;
904 buf.append( Integer.toHexString( val >> 4 ) );
905 buf.append( Integer.toHexString( val & 0xf ) );
906 }
907
908 return buf.toString();
909 }
910
911
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000912 boolean isLogEnabled( int level )
913 {
914 return level <= logLevel;
915 }
916
917
Felix Meschberger4f269292011-10-21 13:52:31 +0000918 void log( int level, String format, Object[] args )
919 {
920 if ( isLogEnabled( level ) )
921 {
922 Throwable throwable = null;
923 String message = format;
924
925 if ( args != null && args.length > 0 )
926 {
927 if ( args[args.length - 1] instanceof Throwable )
928 {
929 throwable = ( Throwable ) args[args.length - 1];
930 }
931 message = MessageFormat.format( format, args );
932 }
933
934 log( level, message, throwable );
935 }
936 }
937
938
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000939 void log( int level, String message, Throwable t )
940 {
Felix Meschberger08282c32009-01-28 07:01:55 +0000941 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +0000942 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000943 if ( log != null )
944 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000945 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000946 return;
947 }
948
Felix Meschberger08282c32009-01-28 07:01:55 +0000949 // Otherwise only log if more serious than the configured level
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000950 if ( isLogEnabled( level ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000951 {
Felix Meschberger08282c32009-01-28 07:01:55 +0000952 String code;
953 switch ( level )
954 {
955 case LogService.LOG_INFO:
956 code = "*INFO *";
957 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000958
Felix Meschberger08282c32009-01-28 07:01:55 +0000959 case LogService.LOG_WARNING:
960 code = "*WARN *";
961 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000962
Felix Meschberger08282c32009-01-28 07:01:55 +0000963 case LogService.LOG_ERROR:
964 code = "*ERROR*";
965 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000966
Felix Meschberger08282c32009-01-28 07:01:55 +0000967 case LogService.LOG_DEBUG:
968 default:
969 code = "*DEBUG*";
970 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000971
Felix Meschberger08282c32009-01-28 07:01:55 +0000972 System.err.println( code + " " + message );
973 if ( t != null )
974 {
975 t.printStackTrace( System.err );
976 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000977 }
978 }
979
Felix Meschberger851c6412009-08-16 18:43:26 +0000980
981 /**
982 * Returns the <code>service.pid</code> property of the service reference as
983 * an array of strings or <code>null</code> if the service reference does
984 * not have a service PID property.
985 * <p>
986 * The service.pid property may be a single string, in which case a single
987 * element array is returned. If the property is an array of string, this
988 * array is returned. If the property is a collection it is assumed to be a
989 * collection of strings and the collection is converted to an array to be
990 * returned. Otherwise (also if the property is not set) <code>null</code>
991 * is returned.
992 *
993 * @throws NullPointerException
994 * if reference is <code>null</code>
995 * @throws ArrayStoreException
996 * if the service pid is a collection and not all elements are
997 * strings.
998 */
999 static String[] getServicePid( ServiceReference reference )
1000 {
1001 Object pidObj = reference.getProperty( Constants.SERVICE_PID );
1002 if ( pidObj instanceof String )
1003 {
1004 return new String[]
1005 { ( String ) pidObj };
1006 }
1007 else if ( pidObj instanceof String[] )
1008 {
1009 return ( String[] ) pidObj;
1010 }
1011 else if ( pidObj instanceof Collection )
1012 {
1013 Collection pidCollection = ( Collection ) pidObj;
1014 return ( String[] ) pidCollection.toArray( new String[pidCollection.size()] );
1015 }
1016
1017 return null;
1018 }
1019
Felix Meschberger41cce522009-08-19 05:54:40 +00001020
1021 static String toString( ServiceReference ref )
1022 {
1023 String[] ocs = ( String[] ) ref.getProperty( "objectClass" );
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001024 StringBuffer buf = new StringBuffer("[");
Felix Meschberger41cce522009-08-19 05:54:40 +00001025 for ( int i = 0; i < ocs.length; i++ )
1026 {
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001027 buf.append(ocs[i]);
Felix Meschberger41cce522009-08-19 05:54:40 +00001028 if ( i < ocs.length - 1 )
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001029 buf.append(", ");
Felix Meschberger41cce522009-08-19 05:54:40 +00001030 }
1031
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001032 buf.append( ", id=" ).append( ref.getProperty( Constants.SERVICE_ID ) );
1033
1034 Bundle provider = ref.getBundle();
1035 if ( provider != null )
1036 {
1037 buf.append( ", bundle=" ).append( provider.getBundleId() );
1038 }
1039 else
1040 {
1041 buf.append( ", unregistered" );
1042 }
1043
1044 buf.append( "]" );
1045 return buf.toString();
Felix Meschberger41cce522009-08-19 05:54:40 +00001046 }
1047
Felix Meschbergerce67d732009-08-20 06:26:35 +00001048
1049 void handleCallBackError( final Throwable error, final ServiceReference target, final ConfigurationImpl config )
1050 {
1051 if ( error instanceof ConfigurationException )
1052 {
1053 final ConfigurationException ce = ( ConfigurationException ) error;
1054 if ( ce.getProperty() != null )
1055 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001056 log( LogService.LOG_ERROR, "{0}: Updating configuration property {1} caused a problem: {2}",
1057 new Object[]
1058 { toString( target ), ce.getProperty(), ce.getReason(), ce } );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001059 }
1060 else
1061 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001062 log( LogService.LOG_ERROR, "{0}: Updating configuration caused a problem: {1}", new Object[]
1063 { toString( target ), ce.getReason(), ce } );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001064 }
1065 }
1066 else
1067 {
1068 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001069 log( LogService.LOG_ERROR, "{0}: Unexpected problem updating {1}", new Object[]
1070 { toString( target ), config, error } );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001071 }
1072
1073 }
1074 }
1075
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001076
Felix Meschberger007c50e2011-10-20 12:39:38 +00001077 /**
1078 * Checks whether the bundle is allowed to receive the configuration
1079 * with the given location binding.
1080 * <p>
1081 * This method implements the logic defined CM 1.4 / 104.4.1:
1082 * <ul>
1083 * <li>If the location is <code>null</code> (the configuration is not
1084 * bound yet), assume the bundle is allowed</li>
1085 * <li>If the location is a single location (no leading "?"), require
1086 * the bundle's location to match</li>
1087 * <li>If the location is a multi-location (leading "?"), assume the
1088 * bundle is allowed if there is no security manager. If there is a
1089 * security manager, check whether the bundle has "target" permission
1090 * on this location.</li>
1091 * </ul>
1092 */
1093 boolean canReceive( final Bundle bundle, final String location )
1094 {
1095 if ( location == null )
1096 {
1097 return true;
1098 }
1099 else if ( location.startsWith( "?" ) )
1100 {
1101 // multi-location
1102 if ( System.getSecurityManager() != null )
1103 {
1104 return bundle.hasPermission( new ConfigurationPermission( location, ConfigurationPermission.TARGET ) );
1105 }
1106 return true;
1107 }
1108 else
1109 {
1110 // single location, must match
1111 return location.equals( bundle.getLocation() );
1112 }
1113 }
1114
1115 // ---------- inner classes
1116
1117 private ServiceHelper createServiceHelper( ConfigurationImpl config )
1118 {
1119 if ( config.getFactoryPid() == null )
1120 {
1121 return new ManagedServiceHelper( config );
1122 }
1123 return new ManagedServiceFactoryHelper( config );
1124 }
1125
1126 private abstract class ServiceHelper
1127 {
1128 protected final ConfigurationImpl config;
1129
1130 private final Dictionary properties;
1131
1132 protected ServiceHelper( ConfigurationImpl config )
1133 {
1134 this.config = config;
1135 this.properties = config.getProperties( true );
1136 }
1137
1138 final ServiceReference[] getServices( )
1139 {
1140 try
1141 {
1142 ServiceReference[] refs = doGetServices();
1143 if ( refs != null && refs.length > 1 )
1144 {
1145 Arrays.sort( refs, RankingComparator.SRV_RANKING );
1146 }
1147 return refs;
1148 }
1149 catch ( InvalidSyntaxException ise )
1150 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001151 log( LogService.LOG_ERROR, "Service selection filter is invalid to update {0}", new Object[]
1152 { config, ise } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001153 }
1154 return null;
1155 }
1156
1157
1158 protected abstract ServiceReference[] doGetServices() throws InvalidSyntaxException;
1159
1160
1161 abstract void provide( ServiceReference service );
1162
1163
1164 abstract void remove( ServiceReference service );
1165
1166
1167 protected Dictionary getProperties( String targetPid, ServiceReference service )
1168 {
1169 Dictionary props = new CaseInsensitiveDictionary( this.properties );
1170 callPlugins( props, targetPid, service, config );
1171 return props;
1172 }
1173 }
1174
1175 private class ManagedServiceHelper extends ServiceHelper
1176 {
1177
1178 protected ManagedServiceHelper( ConfigurationImpl config )
1179 {
1180 super( config );
1181 }
1182
1183
1184 public ServiceReference[] doGetServices() throws InvalidSyntaxException
1185 {
1186 return bundleContext.getServiceReferences( ManagedService.class.getName(), "(" + Constants.SERVICE_PID
1187 + "=" + config.getPid() + ")" );
1188 }
1189
1190
1191 public void provide( ServiceReference service )
1192 {
1193 ManagedService srv = ( ManagedService ) bundleContext.getService( service );
1194 if ( srv != null )
1195 {
1196 try
1197 {
1198 Dictionary props = getProperties( this.config.getPid(), service );
1199 srv.updated( props );
1200 }
1201 catch ( Throwable t )
1202 {
1203 handleCallBackError( t, service, config );
1204 }
1205 finally
1206 {
1207 bundleContext.ungetService( service );
1208 }
1209 }
1210 }
1211
1212
1213 public void remove( ServiceReference service )
1214 {
1215 ManagedService srv = ( ManagedService ) bundleContext.getService( service );
1216 try
1217 {
1218 srv.updated( null );
1219 }
1220 catch ( Throwable t )
1221 {
1222 handleCallBackError( t, service, config );
1223 }
1224 finally
1225 {
1226 bundleContext.ungetService( service );
1227 }
1228 }
1229
1230 }
1231
1232 private class ManagedServiceFactoryHelper extends ServiceHelper
1233 {
1234
1235 protected ManagedServiceFactoryHelper( ConfigurationImpl config )
1236 {
1237 super( config );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001238 }
1239
1240
1241 public ServiceReference[] doGetServices() throws InvalidSyntaxException
1242 {
1243 return bundleContext.getServiceReferences( ManagedServiceFactory.class.getName(), "("
1244 + Constants.SERVICE_PID + "=" + config.getFactoryPid() + ")" );
1245 }
1246
1247
1248 public void provide( ServiceReference service )
1249 {
1250 ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext.getService( service );
1251 if ( srv != null )
1252 {
1253 try
1254 {
1255 Dictionary props = getProperties( this.config.getFactoryPid(), service );
1256 srv.updated( config.getPid(), props );
1257 }
1258 catch ( Throwable t )
1259 {
1260 handleCallBackError( t, service, config );
1261 }
1262 finally
1263 {
1264 bundleContext.ungetService( service );
1265 }
1266 }
1267 }
1268
1269
1270 public void remove( ServiceReference service )
1271 {
1272 ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext.getService( service );
1273 try
1274 {
1275 srv.deleted( config.getPid() );
1276 }
1277 catch ( Throwable t )
1278 {
1279 handleCallBackError( t, service, config );
1280 }
1281 finally
1282 {
1283 bundleContext.ungetService( service );
1284 }
1285 }
1286
1287 }
1288
1289 /**
1290 * The <code>ManagedServiceUpdate</code> updates a freshly registered
1291 * <code>ManagedService</code> with a specific configuration. If a
1292 * ManagedService is registered with multiple PIDs an instance of this
1293 * class is used for each registered PID.
1294 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001295 private class ManagedServiceUpdate implements Runnable
1296 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001297 private final String pid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001298
Felix Meschberger41cce522009-08-19 05:54:40 +00001299 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001300
Felix Meschberger41cce522009-08-19 05:54:40 +00001301 private final ManagedService service;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001302
Felix Meschberger41cce522009-08-19 05:54:40 +00001303 private final ConfigurationImpl config;
1304
1305 private final Dictionary rawProperties;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001306
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001307 private final long lastModificationTime;
1308
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001309 ManagedServiceUpdate( String pid, ServiceReference sr, ManagedService service )
1310 {
1311 this.pid = pid;
1312 this.sr = sr;
1313 this.service = service;
Felix Meschberger41cce522009-08-19 05:54:40 +00001314
1315 // get or load configuration for the pid
1316 ConfigurationImpl config = null;
1317 Dictionary rawProperties = null;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001318 long lastModificationTime = -1;
Felix Meschberger41cce522009-08-19 05:54:40 +00001319 try
1320 {
1321 config = getExistingConfiguration( pid );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001322 if ( config != null )
1323 {
1324 synchronized ( config )
1325 {
1326 rawProperties = config.getProperties( true );
1327 lastModificationTime = config.getLastModificationTime();
1328 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001329 }
1330 }
1331 catch ( IOException ioe )
1332 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001333 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1334 { pid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001335 }
1336
1337 this.config = config;
1338 this.rawProperties = rawProperties;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001339 this.lastModificationTime = lastModificationTime;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001340 }
1341
1342
1343 public void run()
1344 {
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001345 // only update configuration if lastModificationTime is less than
1346 // lastUpdateTime
Felix Meschberger41cce522009-08-19 05:54:40 +00001347 Dictionary properties = rawProperties;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001348 if ( properties != null && config != null && lastModificationTime < config.getLastUpdatedTime() )
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001349 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001350 log(
1351 LogService.LOG_DEBUG,
1352 "Configuration {0} at modification #{1} has already been updated to update #{2}, nothing to be done anymore.",
1353 new Object[]
1354 { config.getPid(), new Long( config.getLastModificationTime() ),
1355 new Long( config.getLastUpdatedTime() ) } );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001356 return;
1357 }
1358
1359 // check configuration and call plugins if existing
Felix Meschberger41cce522009-08-19 05:54:40 +00001360 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001361 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001362 log( LogService.LOG_DEBUG, "Updating configuration {0} to modification #{1}", new Object[]
1363 { pid, new Long( config.getLastModificationTime() ) } );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001364
Felix Meschberger41243192009-01-14 19:59:58 +00001365 Bundle serviceBundle = sr.getBundle();
1366 if ( serviceBundle == null )
1367 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001368 log( LogService.LOG_INFO,
1369 "Service for PID {0} seems to already have been unregistered, not updating with configuration",
1370 new Object[]
1371 { pid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001372 return;
1373 }
1374
Felix Meschberger27689c12011-11-16 08:52:04 +00001375 if ( canReceive( serviceBundle, config.getBundleLocation() ) )
Felix Meschberger2941ef92007-08-20 13:15:16 +00001376 {
Felix Meschberger27689c12011-11-16 08:52:04 +00001377 // 104.4.2 Dynamic Binding
1378 config.tryBindLocation( serviceBundle.getLocation() );
1379
1380 // prepare the configuration for the service (call plugins)
1381 callPlugins( properties, pid, sr, config );
1382 }
1383 else
1384 {
1385 // CM 1.4 / 104.13.2.2 / 104.5.3
1386 // act as if there is no configuration
1387 log(
1388 LogService.LOG_DEBUG,
1389 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}; calling with null",
Felix Meschberger4f269292011-10-21 13:52:31 +00001390 new Object[]
1391 { pid, ConfigurationManager.toString( sr ), config.getBundleLocation() } );
Felix Meschberger27689c12011-11-16 08:52:04 +00001392
1393 // CM 1.4 / 104.5.3 ManagedService.updated must be
1394 // called with null if configuration is no visible
1395 properties = null;
Felix Meschberger2941ef92007-08-20 13:15:16 +00001396 }
1397
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001398 }
1399 else
1400 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001401 // 104.5.3 ManagedService.updated must be called with null
1402 // if no configuration is available
Felix Meschberger41cce522009-08-19 05:54:40 +00001403 properties = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001404 }
1405
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001406 // update the service with the configuration
1407 try
1408 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001409 service.updated( properties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001410 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001411 catch ( Throwable t )
1412 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001413 handleCallBackError( t, sr, config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001414 }
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001415
1416 // update the lastUpdatedTime if there is configuration
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001417 if ( config != null && properties != null )
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001418 {
Felix Meschberger8d9851a2010-08-25 13:22:44 +00001419 config.setLastUpdatedTime( lastModificationTime );
Felix Meschberger4f269292011-10-21 13:52:31 +00001420 log( LogService.LOG_DEBUG, "Updated configuration {0} to update #{1}", new Object[]
1421 { config.getPid(), new Long( config.getLastUpdatedTime() ) } );
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001422 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001423 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001424
Felix Meschberger432e3872008-03-07 14:58:57 +00001425 public String toString()
1426 {
1427 return "ManagedService Update: pid=" + pid;
1428 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001429 }
1430
Felix Meschberger007c50e2011-10-20 12:39:38 +00001431 /**
1432 * The <code>ManagedServiceFactoryUpdate</code> updates a freshly
1433 * registered <code>ManagedServiceFactory</code> with a specific
1434 * configuration. If a ManagedServiceFactory is registered with
1435 * multiple PIDs an instance of this class is used for each registered
1436 * PID.
1437 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001438 private class ManagedServiceFactoryUpdate implements Runnable
1439 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001440 private final String factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001441
Felix Meschberger41cce522009-08-19 05:54:40 +00001442 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001443
Felix Meschberger41cce522009-08-19 05:54:40 +00001444 private final ManagedServiceFactory service;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001445
Felix Meschberger41cce522009-08-19 05:54:40 +00001446 private final Map configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001447
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001448 private final Map stamps;
1449
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001450 ManagedServiceFactoryUpdate( String factoryPid, ServiceReference sr, ManagedServiceFactory service )
1451 {
1452 this.factoryPid = factoryPid;
1453 this.sr = sr;
1454 this.service = service;
Felix Meschberger41cce522009-08-19 05:54:40 +00001455
1456 Factory factory = null;
1457 Map configs = null;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001458 Map stamps = null;
Felix Meschberger41cce522009-08-19 05:54:40 +00001459 try
1460 {
1461 factory = getFactory( factoryPid );
1462 if (factory != null) {
1463 configs = new HashMap();
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001464 stamps = new HashMap();
Felix Meschberger41cce522009-08-19 05:54:40 +00001465 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
1466 {
1467 final String pid = ( String ) pi.next();
1468 ConfigurationImpl cfg;
1469 try
1470 {
1471 cfg = getExistingConfiguration( pid );
1472 }
1473 catch ( IOException ioe )
1474 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001475 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1476 { pid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001477 continue;
1478 }
1479
1480 // sanity check on the configuration
1481 if ( cfg == null )
1482 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001483 log( LogService.LOG_ERROR, "Configuration {0} referred to by factory {1} does not exist",
1484 new Object[]
1485 { pid, factoryPid } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001486 factory.removePID( pid );
1487 factory.storeSilently();
1488 continue;
1489 }
1490 else if ( cfg.isNew() )
1491 {
1492 // Configuration has just been created but not yet updated
1493 // we currently just ignore it and have the update mechanism
1494 // provide the configuration to the ManagedServiceFactory
1495 // As of FELIX-612 (not storing new factory configurations)
1496 // this should not happen. We keep this for added stability
1497 // but raise the logging level to error.
Felix Meschberger4f269292011-10-21 13:52:31 +00001498 log( LogService.LOG_ERROR, "Ignoring new configuration pid={0}", new Object[]
1499 { pid } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001500 continue;
1501 }
1502 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1503 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001504 log( LogService.LOG_ERROR,
1505 "Configuration {0} referred to by factory {1} seems to belong to factory {2}",
1506 new Object[]
1507 { pid, factoryPid, cfg.getFactoryPid() } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001508 factory.removePID( pid );
1509 factory.storeSilently();
1510 continue;
1511 }
1512
1513 // get the configuration properties for later
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001514 synchronized ( cfg )
1515 {
1516 configs.put( cfg, cfg.getProperties( true ) );
1517 stamps.put( cfg, new Long( cfg.getLastModificationTime() ) );
1518 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001519 }
1520 }
1521 }
1522 catch ( IOException ioe )
1523 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001524 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID {0}", new Object[]
1525 { factoryPid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001526 }
1527
Felix Meschberger41cce522009-08-19 05:54:40 +00001528 this.configs = configs;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001529 this.stamps = stamps;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001530 }
1531
1532
1533 public void run()
1534 {
Felix Meschberger41243192009-01-14 19:59:58 +00001535 Bundle serviceBundle = sr.getBundle();
1536 if ( serviceBundle == null )
1537 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001538 log(
1539 LogService.LOG_INFO,
1540 "ManagedServiceFactory for factory PID {0} seems to already have been unregistered, not updating with factory",
1541 new Object[]
1542 { factoryPid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001543 return;
1544 }
1545
Felix Meschberger41cce522009-08-19 05:54:40 +00001546 for ( Iterator ci=configs.entrySet().iterator(); ci.hasNext(); )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001547 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001548 final Map.Entry entry = (Map.Entry) ci.next();
1549 final ConfigurationImpl cfg = (ConfigurationImpl) entry.getKey();
1550 final Dictionary properties = (Dictionary) entry.getValue();
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001551 final long lastModificationTime = ( ( Long ) stamps.get( cfg ) ).longValue();
1552
Felix Meschberger007c50e2011-10-20 12:39:38 +00001553 if ( lastModificationTime <= cfg.getLastUpdatedTime() )
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001554 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001555 log(
1556 LogService.LOG_DEBUG,
1557 "Configuration {0} at modification #{1} has already been updated to update #{2}, nothing to be done anymore.",
1558 new Object[]
1559 { cfg.getPid(), new Long( cfg.getLastModificationTime() ),
1560 new Long( cfg.getLastUpdatedTime() ) } );
1561 continue;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001562 }
1563
Felix Meschberger4f269292011-10-21 13:52:31 +00001564 log( LogService.LOG_DEBUG, "Updating configuration {0} to modification #{1}", new Object[]
1565 { cfg.getPid(), new Long( cfg.getLastModificationTime() ) } );
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001566
Felix Meschberger007c50e2011-10-20 12:39:38 +00001567 // CM 1.4 / 104.13.2.1
1568 if ( !canReceive( serviceBundle, cfg.getBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001569 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001570 log( LogService.LOG_ERROR,
Felix Meschberger4f269292011-10-21 13:52:31 +00001571 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1572 new Object[]
1573 { cfg.getPid(), ConfigurationManager.toString( sr ), cfg.getBundleLocation() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001574 continue;
1575 }
1576
Felix Meschberger007c50e2011-10-20 12:39:38 +00001577 // 104.4.2 Dynamic Binding
1578 cfg.tryBindLocation( serviceBundle.getLocation() );
Felix Meschberger41cce522009-08-19 05:54:40 +00001579
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001580 // prepare the configuration for the service (call plugins)
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001581 // call the plugins with cm.target set to the service's factory PID
1582 // (clarification in Section 104.9.1 of Compendium 4.2)
Felix Meschberger41cce522009-08-19 05:54:40 +00001583 callPlugins( properties, factoryPid, sr, cfg );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001584
Felix Meschbergerce67d732009-08-20 06:26:35 +00001585 // update the service with the configuration (if non-null)
1586 if ( properties != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001587 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001588 log( LogService.LOG_DEBUG, "{0}: Updating configuration pid={1}", new Object[]
1589 { ConfigurationManager.toString( sr ), cfg.getPid() } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001590
Felix Meschbergerce67d732009-08-20 06:26:35 +00001591 try
Felix Meschberger2941ef92007-08-20 13:15:16 +00001592 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001593 service.updated( cfg.getPid(), properties );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001594 }
Felix Meschbergerce67d732009-08-20 06:26:35 +00001595 catch ( Throwable t )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001596 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001597 handleCallBackError( t, sr, cfg );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001598 }
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001599
1600 // update the lastUpdatedTime
Felix Meschberger8d9851a2010-08-25 13:22:44 +00001601 cfg.setLastUpdatedTime( lastModificationTime );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001602
Felix Meschberger4f269292011-10-21 13:52:31 +00001603 log( LogService.LOG_DEBUG, "Updated configuration {0} to update #{1}", new Object[]
1604 { cfg.getPid(), new Long( cfg.getLastUpdatedTime() ) } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001605 }
1606 }
1607 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001608
1609
Felix Meschberger432e3872008-03-07 14:58:57 +00001610 public String toString()
1611 {
1612 return "ManagedServiceFactory Update: factoryPid=" + factoryPid;
1613 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001614 }
1615
Felix Meschberger007c50e2011-10-20 12:39:38 +00001616
1617 /**
1618 * The <code>UpdateConfiguration</code> is used to update
1619 * <code>ManagedService[Factory]</code> services with the configuration
1620 * they are subscribed to. This may cause the configuration to be
1621 * supplied to multiple services.
1622 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001623 private class UpdateConfiguration implements Runnable
1624 {
1625
Felix Meschberger41cce522009-08-19 05:54:40 +00001626 private final ConfigurationImpl config;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001627 private final ServiceHelper helper;
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001628 private final long lastModificationTime;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001629
1630
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001631 UpdateConfiguration( final ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001632 {
1633 this.config = config;
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001634 synchronized ( config )
1635 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001636 this.helper = createServiceHelper( config );
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001637 this.lastModificationTime = config.getLastModificationTime();
1638 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001639 }
1640
1641
1642 public void run()
1643 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001644 if ( lastModificationTime <= config.getLastUpdatedTime() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001645 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001646 log(
1647 LogService.LOG_DEBUG,
1648 "Configuration {0} at modification #{1} has already been updated to update #{2}, nothing to be done anymore.",
1649 new Object[]
1650 { config.getPid(), new Long( config.getLastModificationTime() ),
1651 new Long( config.getLastUpdatedTime() ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001652 return;
1653 }
1654
Felix Meschberger4f269292011-10-21 13:52:31 +00001655 log( LogService.LOG_DEBUG, "Updating configuration {0} to modification #{1}", new Object[]
1656 { config.getPid(), new Long( config.getLastModificationTime() ) } );
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001657
Felix Meschberger007c50e2011-10-20 12:39:38 +00001658 final ServiceReference[] srList = helper.getServices();
1659 if ( srList != null )
Felix Meschberger41cce522009-08-19 05:54:40 +00001660 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001661 // optionally bind dynamically to the first service
1662 config.tryBindLocation( srList[0].getBundle().getLocation() );
1663
1664 final String configBundleLocation = config.getBundleLocation();
1665
1666 // provide configuration to all services from the
1667 // correct bundle
Felix Meschberger41cce522009-08-19 05:54:40 +00001668 for ( int i = 0; i < srList.length; i++ )
1669 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001670 final ServiceReference ref = srList[i];
1671
1672 // CM 1.4 / 104.13.2.2
1673 if ( !canReceive( ref.getBundle(), configBundleLocation ) )
Felix Meschberger41cce522009-08-19 05:54:40 +00001674 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001675 log( LogService.LOG_ERROR,
1676 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1677 new Object[]
1678 { config.getPid(), ConfigurationManager.toString( ref ), configBundleLocation } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001679 continue;
1680 }
1681
1682 helper.provide( ref );
1683
Felix Meschberger4f269292011-10-21 13:52:31 +00001684 log( LogService.LOG_DEBUG, "Updated configuration {0} to update #{1}", new Object[]
1685 { config.getPid(), new Long( config.getLastUpdatedTime() ) } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001686 }
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001687
Felix Meschberger007c50e2011-10-20 12:39:38 +00001688 // update the lastUpdatedTime
1689 config.setLastUpdatedTime( lastModificationTime );
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001690 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001691 }
1692
1693
Felix Meschberger432e3872008-03-07 14:58:57 +00001694 public String toString()
1695 {
1696 return "Update: pid=" + config.getPid();
1697 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001698 }
1699
Felix Meschberger007c50e2011-10-20 12:39:38 +00001700
1701 /**
1702 * The <code>DeleteConfiguration</code> class is used to inform
1703 * <code>ManagedService[Factory]</code> services of a configuration
1704 * being deleted.
1705 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001706 private class DeleteConfiguration implements Runnable
1707 {
Felix Meschberger66423332007-08-22 08:46:34 +00001708
Felix Meschbergerce67d732009-08-20 06:26:35 +00001709 private final ConfigurationImpl config;
Felix Meschbergerc12db8c2009-08-19 06:43:59 +00001710 private final String configLocation;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001711
1712
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001713 DeleteConfiguration( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001714 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001715 /*
1716 * NOTE: We keep the configuration because it might be cleared just
1717 * after calling this method. The pid and factoryPid fields are
1718 * final and cannot be reset.
1719 */
1720 this.config = config;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001721 this.configLocation = config.getBundleLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001722 }
1723
1724
1725 public void run()
1726 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001727 final String pid = config.getPid();
1728 final String factoryPid = config.getFactoryPid();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001729 final ServiceHelper helper = createServiceHelper( config );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001730
Felix Meschberger007c50e2011-10-20 12:39:38 +00001731 ServiceReference[] srList = helper.getServices( );
1732 if ( srList != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001733 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001734 for ( int i = 0; i < srList.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001735 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001736 final ServiceReference sr = srList[i];
1737 if ( canReceive( sr.getBundle(), configLocation ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001738 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001739 helper.remove( sr );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001740 }
1741 }
1742 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001743
1744 if ( factoryPid != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001745 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001746 // remove the pid from the factory
1747 try
1748 {
1749 Factory factory = getFactory( factoryPid );
1750 factory.removePID( pid );
1751 factory.store();
1752 }
1753 catch ( IOException ioe )
1754 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001755 log( LogService.LOG_ERROR, "Failed removing {0} from the factory {1}", new Object[]
1756 { pid, factoryPid, ioe } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001757 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001758 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001759 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001760
Felix Meschberger432e3872008-03-07 14:58:57 +00001761 public String toString()
1762 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001763 return "Delete: pid=" + config.getPid();
Felix Meschberger432e3872008-03-07 14:58:57 +00001764 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001765 }
1766
Felix Meschberger007c50e2011-10-20 12:39:38 +00001767 private class LocationChanged implements Runnable
1768 {
1769 private final ConfigurationImpl config;
1770 private final String oldLocation;
1771
1772
1773 LocationChanged( ConfigurationImpl config, String oldLocation )
1774 {
1775 this.config = config;
1776 this.oldLocation = oldLocation;
1777 }
1778
1779
1780 public void run()
1781 {
1782 ServiceHelper helper = createServiceHelper( this.config );
1783 ServiceReference[] srList = helper.getServices( );
1784 if ( srList != null )
1785 {
1786 // make sure the config is dynamically bound to the first
1787 // service if it has been unbound causing this update
1788 config.tryBindLocation( srList[0].getBundle().getLocation() );
1789
1790 for ( int i = 0; i < srList.length; i++ )
1791 {
1792 final ServiceReference sr = srList[i];
1793 final boolean wasVisible = canReceive( sr.getBundle(), oldLocation );
1794 final boolean isVisible = canReceive( sr.getBundle(), config.getBundleLocation() );
1795 if ( wasVisible && !isVisible )
1796 {
1797 // call deleted method
1798 helper.remove( sr );
Felix Meschberger4f269292011-10-21 13:52:31 +00001799 log( LogService.LOG_DEBUG, "Configuration {0} revoked from {1} (no more visibility)",
1800 new Object[]
1801 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001802 }
1803 else if ( !wasVisible && isVisible )
1804 {
1805 // call updated method
1806 helper.provide( sr );
Felix Meschberger4f269292011-10-21 13:52:31 +00001807 log( LogService.LOG_DEBUG, "Configuration {0} provided to {1} (new visibility)", new Object[]
1808 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger35658d52011-10-20 21:43:58 +00001809 }
Felix Meschberger4f269292011-10-21 13:52:31 +00001810 else
Felix Meschberger35658d52011-10-20 21:43:58 +00001811 {
1812 // same visibility as before
Felix Meschberger4f269292011-10-21 13:52:31 +00001813 log( LogService.LOG_DEBUG, "Unmodified visibility to configuration {0} for {1}", new Object[]
1814 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001815 }
1816 }
1817 }
1818 }
1819
1820
1821 public String toString()
1822 {
1823 return "Location Changed (pid=" + config.getPid() + "): " + oldLocation + " ==> "
1824 + config.getBundleLocation();
1825 }
1826 }
1827
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001828 private class FireConfigurationEvent implements Runnable
1829 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001830 private final int type;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001831
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001832 private final String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001833
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001834 private final String factoryPid;
1835
1836 private final ServiceReference[] listenerReferences;
1837
1838 private final ConfigurationListener[] listeners;
1839
1840 private final Bundle[] listenerProvider;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001841
1842
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001843 private FireConfigurationEvent( final int type, final String pid, final String factoryPid)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001844 {
1845 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001846 this.pid = pid;
1847 this.factoryPid = factoryPid;
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001848
1849 final ServiceReference[] srs = configurationListenerTracker.getServiceReferences();
1850 if ( srs == null || srs.length == 0 )
1851 {
1852 this.listenerReferences = null;
1853 this.listeners = null;
1854 this.listenerProvider = null;
1855 }
1856 else
1857 {
1858 this.listenerReferences = srs;
1859 this.listeners = new ConfigurationListener[srs.length];
1860 this.listenerProvider = new Bundle[srs.length];
1861 for ( int i = 0; i < srs.length; i++ )
1862 {
1863 this.listeners[i] = ( ConfigurationListener ) configurationListenerTracker.getService( srs[i] );
1864 this.listenerProvider[i] = srs[i].getBundle();
1865 }
1866 }
1867 }
1868
1869
1870 boolean hasConfigurationEventListeners()
1871 {
1872 return this.listenerReferences != null;
1873 }
1874
1875
1876 String getTypeName()
1877 {
1878 switch ( type )
1879 {
1880 case ConfigurationEvent.CM_DELETED:
1881 return "CM_DELETED";
1882 case ConfigurationEvent.CM_UPDATED:
1883 return "CM_UPDATED";
Felix Meschberger007c50e2011-10-20 12:39:38 +00001884 case ConfigurationEvent.CM_LOCATION_CHANGED:
1885 return "CM_LOCATION_CHANGED";
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001886 default:
1887 return "<UNKNOWN(" + type + ")>";
1888 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001889 }
1890
1891
1892 public void run()
1893 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001894 final String typeName = getTypeName();
1895 final ConfigurationEvent event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001896
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001897 for ( int i = 0; i < listeners.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001898 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001899 if ( listenerProvider[i].getState() == Bundle.ACTIVE )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001900 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001901 log( LogService.LOG_DEBUG, "Sending {0} event for {1} to {2}", new Object[]
1902 { typeName, pid, ConfigurationManager.toString( listenerReferences[i] ) } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001903
1904 try
1905 {
1906 listeners[i].configurationEvent( event );
1907 }
1908 catch ( Throwable t )
1909 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001910 log( LogService.LOG_ERROR, "Unexpected problem delivering configuration event to {0}",
1911 new Object[]
1912 { ConfigurationManager.toString( listenerReferences[i] ), t } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001913 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001914 }
1915 }
1916 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001917
Felix Meschberger432e3872008-03-07 14:58:57 +00001918 public String toString()
1919 {
1920 return "Fire ConfigurationEvent: pid=" + pid;
1921 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001922 }
1923
Felix Meschberger41cce522009-08-19 05:54:40 +00001924 private static class ManagedServiceTracker extends ServiceTracker
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001925 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001926
Felix Meschberger41cce522009-08-19 05:54:40 +00001927 private final ConfigurationManager cm;
1928
1929
1930 ManagedServiceTracker( ConfigurationManager cm )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001931 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001932 super( cm.bundleContext, ManagedService.class.getName(), null );
Carsten Ziegeler41683982007-12-27 08:35:27 +00001933 this.cm = cm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001934 open();
1935 }
1936
1937
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001938 public Object addingService( ServiceReference reference )
1939 {
Felix Meschberger05d89e12011-11-03 23:37:10 +00001940 Object service = super.addingService( reference );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001941
1942 // configure the managed service
Felix Meschberger05d89e12011-11-03 23:37:10 +00001943 final String[] pids;
1944 if ( service instanceof ManagedService )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001945 {
Felix Meschberger05d89e12011-11-03 23:37:10 +00001946 pids = getServicePid( reference );
1947 cm.configure( pids, reference, ( ManagedService ) service );
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001948 }
1949 else
1950 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001951 cm.log( LogService.LOG_WARNING, "Service {0} is not a ManagedService", new Object[]
Felix Meschberger05d89e12011-11-03 23:37:10 +00001952 { service } );
1953 pids = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001954 }
1955
Felix Meschberger05d89e12011-11-03 23:37:10 +00001956 return new ManagedServiceHolder( service, pids );
1957 }
1958
1959
1960 public void modifiedService( ServiceReference reference, Object service )
1961 {
1962 ManagedServiceHolder holder = ( ManagedServiceHolder ) service;
1963 String[] pids = getServicePid( reference );
1964
1965 if ( holder.isDifferentPids( pids ) )
1966 {
1967 cm.configure( pids, reference, ( ManagedService ) holder.getManagedService() );
1968 holder.setConfiguredPids( pids );
1969 }
1970 }
1971
1972
1973 public void removedService( ServiceReference reference, Object service )
1974 {
1975 final Object serviceObject = ( ( ManagedServiceHolder ) service ).getManagedService();
1976 super.removedService( reference, serviceObject );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001977 }
1978 }
1979
Felix Meschberger41cce522009-08-19 05:54:40 +00001980 private static class ManagedServiceFactoryTracker extends ServiceTracker
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001981 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001982 private final ConfigurationManager cm;
1983
1984
1985 ManagedServiceFactoryTracker( ConfigurationManager cm )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001986 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001987 super( cm.bundleContext, ManagedServiceFactory.class.getName(), null );
1988 this.cm = cm;
1989 open();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001990 }
1991
1992
1993 public Object addingService( ServiceReference reference )
1994 {
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001995 Object serviceObject = super.addingService( reference );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001996
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001997 // configure the managed service factory
Felix Meschberger05d89e12011-11-03 23:37:10 +00001998 final String[] pids;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001999 if ( serviceObject instanceof ManagedServiceFactory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002000 {
Felix Meschberger05d89e12011-11-03 23:37:10 +00002001 pids = getServicePid( reference );
2002 cm.configure( pids, reference, ( ManagedServiceFactory ) serviceObject );
Felix Meschberger2fd5b582007-12-10 10:32:29 +00002003 }
2004 else
2005 {
Felix Meschberger4f269292011-10-21 13:52:31 +00002006 cm.log( LogService.LOG_WARNING, "Service {0} is not a ManagedServiceFactory", new Object[]
2007 { serviceObject } );
Felix Meschberger05d89e12011-11-03 23:37:10 +00002008 pids = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002009 }
2010
Felix Meschberger05d89e12011-11-03 23:37:10 +00002011 return new ManagedServiceHolder( serviceObject, pids );
2012 }
2013
2014
2015 public void modifiedService( ServiceReference reference, Object service )
2016 {
2017 ManagedServiceHolder holder = ( ManagedServiceHolder ) service;
2018 String[] pids = getServicePid( reference );
2019
2020 if ( holder.isDifferentPids( pids ) )
2021 {
2022 cm.configure( pids, reference, ( ManagedServiceFactory ) holder.getManagedService() );
2023 holder.setConfiguredPids( pids );
2024 }
2025
2026 super.modifiedService( reference, service );
2027 }
2028
2029
2030 public void removedService( ServiceReference reference, Object service )
2031 {
2032 final Object serviceObject = ( ( ManagedServiceHolder ) service ).getManagedService();
2033 super.removedService( reference, serviceObject );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002034 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002035 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00002036
Felix Meschberger05d89e12011-11-03 23:37:10 +00002037 private static class ManagedServiceHolder
2038 {
2039 private final Object managedService;
2040 private String[] configuredPids;
Felix Meschberger007c50e2011-10-20 12:39:38 +00002041
Felix Meschberger05d89e12011-11-03 23:37:10 +00002042
2043 ManagedServiceHolder( final Object managedService, final String[] configuredPids )
2044 {
2045 this.managedService = managedService;
2046 this.configuredPids = configuredPids;
2047 }
2048
2049
2050 public Object getManagedService()
2051 {
2052 return managedService;
2053 }
2054
2055
2056 public void setConfiguredPids( String[] configuredPids )
2057 {
2058 this.configuredPids = configuredPids;
2059 }
2060
2061
2062 boolean isDifferentPids( final String[] pids )
2063 {
2064 if ( this.configuredPids == null && pids == null )
2065 {
2066 return false;
2067 }
2068 else if ( this.configuredPids == null )
2069 {
2070 return true;
2071 }
2072 else if ( pids == null )
2073 {
2074 return true;
2075 }
2076 else if ( this.configuredPids.length != pids.length )
2077 {
2078 return true;
2079 }
2080 else
2081 {
2082 HashSet thisPids = new HashSet( Arrays.asList( this.configuredPids ) );
2083 HashSet otherPids = new HashSet( Arrays.asList( pids ) );
2084 return !thisPids.equals( otherPids );
2085 }
2086 }
2087 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002088}