blob: 83ee3863c5255655e3cde918d80a1b5b72fdd433 [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 Meschberger2941ef92007-08-20 13:15:16 +0000437 return config;
438 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000439
Felix Meschberger2941ef92007-08-20 13:15:16 +0000440 PersistenceManager[] pmList = getPersistenceManagers();
441 for ( int i = 0; i < pmList.length; i++ )
442 {
443 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000444 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000445 Dictionary props = pmList[i].load( pid );
446 config = new ConfigurationImpl( this, pmList[i], props );
447 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000448 }
449 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000450
Felix Meschberger2941ef92007-08-20 13:15:16 +0000451 // neither the cache nor any persistence manager has configuration
452 return null;
453 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000454
455
Felix Meschberger2941ef92007-08-20 13:15:16 +0000456 ConfigurationImpl getConfiguration( String pid, String bundleLocation ) throws IOException
457 {
458 // check for existing (cached or persistent) configuration
459 ConfigurationImpl config = getExistingConfiguration( pid );
460 if ( config != null )
461 {
462 return config;
463 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000464
Felix Meschberger2941ef92007-08-20 13:15:16 +0000465 // else create new configuration also setting the bundle location
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000466 // and cache the new configuration
467 config = createConfiguration( pid, null, bundleLocation );
468 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000469 }
470
471
472 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
473 throws IOException, InvalidSyntaxException
474 {
475 Filter filter = null;
476 if ( filterString != null )
477 {
478 filter = bundleContext.createFilter( filterString );
479 }
480
Felix Meschberger4f269292011-10-21 13:52:31 +0000481 log( LogService.LOG_DEBUG, "Listing configurations matching {0}", new Object[]
482 { filterString } );
483
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000484 List configList = new ArrayList();
485
486 PersistenceManager[] pmList = getPersistenceManagers();
487 for ( int i = 0; i < pmList.length; i++ )
488 {
489 Enumeration configs = pmList[i].getDictionaries();
490 while ( configs.hasMoreElements() )
491 {
492 Dictionary config = ( Dictionary ) configs.nextElement();
493
494 // ignore non-Configuration dictionaries
Felix Meschberger86a0d172007-07-04 07:15:01 +0000495 String pid = ( String ) config.get( Constants.SERVICE_PID );
496 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000497 {
498 continue;
499 }
500
Felix Meschberger007c50e2011-10-20 12:39:38 +0000501 // CM 1.4 / 104.13.2.3 Permission required
502 if ( !configurationAdmin.hasPermission( ( String ) config
503 .get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000504 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000505 log(
506 LogService.LOG_DEBUG,
507 "Omitting configuration {0}: No permission for {1} on {2}",
508 new Object[]
509 { config.get( Constants.SERVICE_PID ), configurationAdmin.getBundle().getLocation(),
510 config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000511 continue;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000512 }
513
514 // check filter
515 if ( filter == null || filter.match( config ) )
516 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000517 // ensure the service.pid and returned a cached config if available
518 ConfigurationImpl cfg = getCachedConfiguration( pid );
519 if ( cfg == null )
520 {
521 cfg = new ConfigurationImpl( this, pmList[i], config );
522 }
523
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000524 // FELIX-611: Ignore configuration objects without props
525 if ( !cfg.isNew() )
526 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000527 log( LogService.LOG_DEBUG, "Adding configuration {0}", new Object[]
528 { config.get( Constants.SERVICE_PID ) } );
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000529 configList.add( cfg );
530 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000531 else
532 {
533 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Is new", new Object[]
534 { config.get( Constants.SERVICE_PID ) } );
535 }
536 } else {
537 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Does not match filter", new Object[]
538 { config.get( Constants.SERVICE_PID ) } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000539 }
540 }
541 }
542
Felix Meschberger8faceff2007-07-04 07:19:48 +0000543 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000544 .size()] );
545 }
546
547
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000548 void deleted( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000549 {
550 // remove the configuration from the cache
551 removeConfiguration( config );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000552 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, config.getPid(), config.getFactoryPid() );
553 updateThread.schedule( new DeleteConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000554 log( LogService.LOG_DEBUG, "DeleteConfiguration({0}) scheduled", new Object[]
555 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000556 }
557
558
Felix Meschbergerce67d732009-08-20 06:26:35 +0000559 void updated( ConfigurationImpl config, boolean fireEvent )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000560 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000561 if ( fireEvent )
562 {
563 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPid(), config.getFactoryPid() );
564 }
565 updateThread.schedule( new UpdateConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000566 log( LogService.LOG_DEBUG, "UpdateConfiguration({0}) scheduled", new Object[]
567 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000568 }
569
570
Felix Meschberger007c50e2011-10-20 12:39:38 +0000571 void locationChanged( ConfigurationImpl config, String oldLocation )
572 {
573 fireConfigurationEvent( ConfigurationEvent.CM_LOCATION_CHANGED, config.getPid(), config.getFactoryPid() );
Felix Meschberger35658d52011-10-20 21:43:58 +0000574 if ( oldLocation != null && !config.isNew() )
Felix Meschberger007c50e2011-10-20 12:39:38 +0000575 {
576 updateThread.schedule( new LocationChanged( config, oldLocation ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000577 log( LogService.LOG_DEBUG, "LocationChanged({0}, {1}=>{2}) scheduled", new Object[]
578 { config.getPid(), oldLocation, config.getBundleLocation() } );
Felix Meschberger35658d52011-10-20 21:43:58 +0000579 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000580 else
Felix Meschberger35658d52011-10-20 21:43:58 +0000581 {
582 log( LogService.LOG_DEBUG,
Felix Meschberger4f269292011-10-21 13:52:31 +0000583 "LocationChanged not scheduled for {0} (old location is null or configuration is new)", new Object[]
584 { config.getPid() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000585 }
586 }
587
588
Felix Meschberger66423332007-08-22 08:46:34 +0000589 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000590 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000591 FireConfigurationEvent event = new FireConfigurationEvent( type, pid, factoryPid );
592 if ( event.hasConfigurationEventListeners() )
593 {
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000594 eventThread.schedule( event );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000595 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000596 else
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000597 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000598 log( LogService.LOG_DEBUG, "No ConfigurationListeners to send {0} event to.", new Object[]
599 { event.getTypeName() } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000600 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000601 }
602
603
604 // ---------- BundleListener -----------------------------------------------
605
606 public void bundleChanged( BundleEvent event )
607 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000608 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000609 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000610 final String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000611
Felix Meschberger6a698df2009-08-16 18:38:46 +0000612 // we only reset dynamic bindings, which are only present in
613 // cached configurations, hence only consider cached configs here
614 final ConfigurationImpl[] configs = getCachedConfigurations();
615 for ( int i = 0; i < configs.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000616 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000617 final ConfigurationImpl cfg = configs[i];
Felix Meschberger41cce522009-08-19 05:54:40 +0000618 if ( location.equals( cfg.getDynamicBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000619 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000620 cfg.setDynamicBundleLocation( null, true );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000621 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000622 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000623 }
624 }
625
626
627 // ---------- internal -----------------------------------------------------
628
629 private PersistenceManager[] getPersistenceManagers()
630 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000631 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
632 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000633 {
634
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000635 List pmList = new ArrayList();
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000636 PersistenceManager[] pm;
637
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000638 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
639 if ( refs == null || refs.length == 0 )
640 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000641 pm = new PersistenceManager[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000642 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000643 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000644 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000645 // sort the references according to the cmRanking property
Felix Meschberger007c50e2011-10-20 12:39:38 +0000646 if ( refs.length > 1 )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000647 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000648 Arrays.sort( refs, RankingComparator.SRV_RANKING );
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000649 }
650
651 // create the service array from the sorted set of referenecs
Felix Meschberger007c50e2011-10-20 12:39:38 +0000652 for ( int i = 0; i < refs.length; i++ )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000653 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000654 Object service = persistenceManagerTracker.getService( refs[i] );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000655 if ( service != null )
656 {
Felix Meschbergera86cdfc2010-08-25 09:32:36 +0000657 pmList.add( new CachingPersistenceManagerProxy( ( PersistenceManager ) service ) );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000658 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000659 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000660
661 pm = ( PersistenceManager[] ) pmList.toArray( new PersistenceManager[pmList.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000662 }
663
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000664 pmtCount = pm.length;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000665 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000666 }
667
668 return persistenceManagers;
669 }
670
671
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000672 private ServiceReference getServiceReference()
673 {
674 ServiceRegistration reg = configurationAdminRegistration;
675 return ( reg != null ) ? reg.getReference() : null;
676 }
677
678
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000679 private void configure( ServiceReference sr, ManagedService service )
680 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000681 String[] pids = getServicePid( sr );
682 if ( pids != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000683 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000684 for ( int i = 0; i < pids.length; i++ )
685 {
686 ManagedServiceUpdate update = new ManagedServiceUpdate( pids[i], sr, service );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000687 updateThread.schedule( update );
Felix Meschberger4f269292011-10-21 13:52:31 +0000688 log( LogService.LOG_DEBUG, "ManagedServiceUpdate({0}) scheduled", new Object[]
689 { pids[i] } );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000690 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000691 }
Felix Meschberger851c6412009-08-16 18:43:26 +0000692 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000693
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000694
695 private void configure( ServiceReference sr, ManagedServiceFactory service )
696 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000697 String[] pids = getServicePid( sr );
698 if ( pids != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000699 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000700 for ( int i = 0; i < pids.length; i++ )
701 {
702 ManagedServiceFactoryUpdate update = new ManagedServiceFactoryUpdate( pids[i], sr, service );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000703 updateThread.schedule( update );
Felix Meschberger4f269292011-10-21 13:52:31 +0000704 log( LogService.LOG_DEBUG, "ManagedServiceFactoryUpdate({0}) scheduled", new Object[]
705 { pids[i] } );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000706 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000707 }
Felix Meschberger851c6412009-08-16 18:43:26 +0000708 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000709
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000710
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000711 /**
712 * Factory method to create a new configuration object. The configuration
713 * object returned is not stored in configuration cache and only persisted
714 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000715 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000716 * @param pid
717 * The PID of the new configuration object. Must not be
718 * <code>null</code>.
719 * @param factoryPid
720 * The factory PID of the new configuration. Not
Felix Meschberger6a698df2009-08-16 18:38:46 +0000721 * <code>null</code> if the new configuration object belongs to a
722 * factory. The configuration object will not be persisted if
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000723 * this parameter is not <code>null</code>.
724 * @param bundleLocation
725 * The bundle location of the bundle to which the configuration
Felix Meschberger6a698df2009-08-16 18:38:46 +0000726 * belongs or <code>null</code> if the configuration is not bound
727 * yet.
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000728 * @return The new configuration object
729 * @throws IOException
730 * May be thrown if an error occurrs persisting the new
731 * configuration object.
732 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000733 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000734 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000735 log( LogService.LOG_DEBUG, "createConfiguration({0}, {1}, {2})", new Object[]
736 { pid, factoryPid, bundleLocation } );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000737 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000738 }
739
740
741 Factory getFactory( String factoryPid ) throws IOException
742 {
Felix Meschbergerf4631322008-03-10 12:32:35 +0000743 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000744 if ( factory != null )
745 {
746 return factory;
747 }
748
749 PersistenceManager[] pmList = getPersistenceManagers();
750 for ( int i = 0; i < pmList.length; i++ )
751 {
752 if ( Factory.exists( pmList[i], factoryPid ) )
753 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000754 factory = Factory.load( this, pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000755 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000756 return factory;
757 }
758 }
759
760 // if getting here, there is no configuration yet, optionally create new
761 return createFactory( factoryPid );
762 }
763
764
765 Factory createFactory( String factoryPid )
766 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000767 Factory factory = new Factory( this, getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000768 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000769 return factory;
770 }
771
772
Felix Meschberger2941ef92007-08-20 13:15:16 +0000773 /**
774 * Calls the registered configuration plugins on the given configuration
Felix Meschberger41cce522009-08-19 05:54:40 +0000775 * properties from the given configuration object unless the configuration
776 * has just been created and not been updated yet.
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000777 *
Felix Meschberger41cce522009-08-19 05:54:40 +0000778 * @param props The configuraiton properties run through the registered
779 * ConfigurationPlugin services. This may be <code>null</code>
780 * in which case this method just immediately returns.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000781 * @param targetPid The identification of the configuration update used to
782 * select the plugins according to their cm.target service
783 * property
Felix Meschberger2941ef92007-08-20 13:15:16 +0000784 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000785 * is to be updated with configuration
Felix Meschberger2941ef92007-08-20 13:15:16 +0000786 * @param cfg The configuration object whose properties have to be passed
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000787 * through the plugins
Felix Meschberger2941ef92007-08-20 13:15:16 +0000788 */
Felix Meschberger41cce522009-08-19 05:54:40 +0000789 private void callPlugins( final Dictionary props, final String targetPid, final ServiceReference sr,
790 final ConfigurationImpl cfg )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000791 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000792 // guard against NPE for new configuration never updated
793 if (props == null) {
Felix Meschberger41cce522009-08-19 05:54:40 +0000794 return;
Felix Meschberger2941ef92007-08-20 13:15:16 +0000795 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000796
797 ServiceReference[] plugins = null;
798 try
799 {
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000800 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000801 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000802 }
803 catch ( InvalidSyntaxException ise )
804 {
805 // no filter, no exception ...
806 }
807
808 // abort early if there are no plugins
809 if ( plugins == null || plugins.length == 0 )
810 {
Felix Meschberger41cce522009-08-19 05:54:40 +0000811 return;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000812 }
813
814 // sort the plugins by their service.cmRanking
Felix Meschberger007c50e2011-10-20 12:39:38 +0000815 if ( plugins.length > 1 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000816 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000817 Arrays.sort( plugins, RankingComparator.CM_RANKING );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000818 }
819
820 // call the plugins in order
Felix Meschberger007c50e2011-10-20 12:39:38 +0000821 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000822 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000823 ServiceReference pluginRef = plugins[i];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000824 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000825 if ( plugin != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000826 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000827 try
828 {
829 plugin.modifyConfiguration( sr, props );
830 }
831 catch ( Throwable t )
832 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000833 log( LogService.LOG_ERROR, "Unexpected problem calling configuration plugin {0}", new Object[]
834 { toString( pluginRef ), t } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000835 }
836 finally
837 {
838 // ensure ungetting the plugin
839 bundleContext.ungetService( pluginRef );
840 }
841 cfg.setAutoProperties( props, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000842 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000843 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000844 }
845
846
847 /**
848 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000849 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000850 * @param factoryPid
851 * @return
852 */
853 private static String createPid( String factoryPid )
854 {
Felix Meschberger417f66c2011-02-04 11:25:23 +0000855 Random ng = numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000856 if ( ng == null )
857 {
Felix Meschberger417f66c2011-02-04 11:25:23 +0000858 // FELIX-2771 Secure Random not available on Mika
859 try
860 {
861 ng = new SecureRandom();
862 }
863 catch ( Throwable t )
864 {
865 // fall back to Random
866 ng = new Random();
867 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000868 }
869
870 byte[] randomBytes = new byte[16];
871 ng.nextBytes( randomBytes );
872 randomBytes[6] &= 0x0f; /* clear version */
873 randomBytes[6] |= 0x40; /* set to version 4 */
874 randomBytes[8] &= 0x3f; /* clear variant */
875 randomBytes[8] |= 0x80; /* set to IETF variant */
876
877 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
878
879 // prefix the new pid with the factory pid
880 buf.append( factoryPid ).append( "." );
881
882 // serialize the UUID into the buffer
883 for ( int i = 0; i < randomBytes.length; i++ )
884 {
885
886 if ( i == 4 || i == 6 || i == 8 || i == 10 )
887 {
888 buf.append( '-' );
889 }
890
891 int val = randomBytes[i] & 0xff;
892 buf.append( Integer.toHexString( val >> 4 ) );
893 buf.append( Integer.toHexString( val & 0xf ) );
894 }
895
896 return buf.toString();
897 }
898
899
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000900 boolean isLogEnabled( int level )
901 {
902 return level <= logLevel;
903 }
904
905
Felix Meschberger4f269292011-10-21 13:52:31 +0000906 void log( int level, String format, Object[] args )
907 {
908 if ( isLogEnabled( level ) )
909 {
910 Throwable throwable = null;
911 String message = format;
912
913 if ( args != null && args.length > 0 )
914 {
915 if ( args[args.length - 1] instanceof Throwable )
916 {
917 throwable = ( Throwable ) args[args.length - 1];
918 }
919 message = MessageFormat.format( format, args );
920 }
921
922 log( level, message, throwable );
923 }
924 }
925
926
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000927 void log( int level, String message, Throwable t )
928 {
Felix Meschberger08282c32009-01-28 07:01:55 +0000929 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +0000930 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000931 if ( log != null )
932 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000933 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000934 return;
935 }
936
Felix Meschberger08282c32009-01-28 07:01:55 +0000937 // Otherwise only log if more serious than the configured level
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000938 if ( isLogEnabled( level ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000939 {
Felix Meschberger08282c32009-01-28 07:01:55 +0000940 String code;
941 switch ( level )
942 {
943 case LogService.LOG_INFO:
944 code = "*INFO *";
945 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000946
Felix Meschberger08282c32009-01-28 07:01:55 +0000947 case LogService.LOG_WARNING:
948 code = "*WARN *";
949 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000950
Felix Meschberger08282c32009-01-28 07:01:55 +0000951 case LogService.LOG_ERROR:
952 code = "*ERROR*";
953 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000954
Felix Meschberger08282c32009-01-28 07:01:55 +0000955 case LogService.LOG_DEBUG:
956 default:
957 code = "*DEBUG*";
958 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000959
Felix Meschberger08282c32009-01-28 07:01:55 +0000960 System.err.println( code + " " + message );
961 if ( t != null )
962 {
963 t.printStackTrace( System.err );
964 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000965 }
966 }
967
Felix Meschberger851c6412009-08-16 18:43:26 +0000968
969 /**
970 * Returns the <code>service.pid</code> property of the service reference as
971 * an array of strings or <code>null</code> if the service reference does
972 * not have a service PID property.
973 * <p>
974 * The service.pid property may be a single string, in which case a single
975 * element array is returned. If the property is an array of string, this
976 * array is returned. If the property is a collection it is assumed to be a
977 * collection of strings and the collection is converted to an array to be
978 * returned. Otherwise (also if the property is not set) <code>null</code>
979 * is returned.
980 *
981 * @throws NullPointerException
982 * if reference is <code>null</code>
983 * @throws ArrayStoreException
984 * if the service pid is a collection and not all elements are
985 * strings.
986 */
987 static String[] getServicePid( ServiceReference reference )
988 {
989 Object pidObj = reference.getProperty( Constants.SERVICE_PID );
990 if ( pidObj instanceof String )
991 {
992 return new String[]
993 { ( String ) pidObj };
994 }
995 else if ( pidObj instanceof String[] )
996 {
997 return ( String[] ) pidObj;
998 }
999 else if ( pidObj instanceof Collection )
1000 {
1001 Collection pidCollection = ( Collection ) pidObj;
1002 return ( String[] ) pidCollection.toArray( new String[pidCollection.size()] );
1003 }
1004
1005 return null;
1006 }
1007
Felix Meschberger41cce522009-08-19 05:54:40 +00001008
1009 static String toString( ServiceReference ref )
1010 {
1011 String[] ocs = ( String[] ) ref.getProperty( "objectClass" );
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001012 StringBuffer buf = new StringBuffer("[");
Felix Meschberger41cce522009-08-19 05:54:40 +00001013 for ( int i = 0; i < ocs.length; i++ )
1014 {
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001015 buf.append(ocs[i]);
Felix Meschberger41cce522009-08-19 05:54:40 +00001016 if ( i < ocs.length - 1 )
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001017 buf.append(", ");
Felix Meschberger41cce522009-08-19 05:54:40 +00001018 }
1019
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001020 buf.append( ", id=" ).append( ref.getProperty( Constants.SERVICE_ID ) );
1021
1022 Bundle provider = ref.getBundle();
1023 if ( provider != null )
1024 {
1025 buf.append( ", bundle=" ).append( provider.getBundleId() );
1026 }
1027 else
1028 {
1029 buf.append( ", unregistered" );
1030 }
1031
1032 buf.append( "]" );
1033 return buf.toString();
Felix Meschberger41cce522009-08-19 05:54:40 +00001034 }
1035
Felix Meschbergerce67d732009-08-20 06:26:35 +00001036
1037 void handleCallBackError( final Throwable error, final ServiceReference target, final ConfigurationImpl config )
1038 {
1039 if ( error instanceof ConfigurationException )
1040 {
1041 final ConfigurationException ce = ( ConfigurationException ) error;
1042 if ( ce.getProperty() != null )
1043 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001044 log( LogService.LOG_ERROR, "{0}: Updating configuration property {1} caused a problem: {2}",
1045 new Object[]
1046 { toString( target ), ce.getProperty(), ce.getReason(), ce } );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001047 }
1048 else
1049 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001050 log( LogService.LOG_ERROR, "{0}: Updating configuration caused a problem: {1}", new Object[]
1051 { toString( target ), ce.getReason(), ce } );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001052 }
1053 }
1054 else
1055 {
1056 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001057 log( LogService.LOG_ERROR, "{0}: Unexpected problem updating {1}", new Object[]
1058 { toString( target ), config, error } );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001059 }
1060
1061 }
1062 }
1063
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001064
Felix Meschberger007c50e2011-10-20 12:39:38 +00001065 /**
1066 * Checks whether the bundle is allowed to receive the configuration
1067 * with the given location binding.
1068 * <p>
1069 * This method implements the logic defined CM 1.4 / 104.4.1:
1070 * <ul>
1071 * <li>If the location is <code>null</code> (the configuration is not
1072 * bound yet), assume the bundle is allowed</li>
1073 * <li>If the location is a single location (no leading "?"), require
1074 * the bundle's location to match</li>
1075 * <li>If the location is a multi-location (leading "?"), assume the
1076 * bundle is allowed if there is no security manager. If there is a
1077 * security manager, check whether the bundle has "target" permission
1078 * on this location.</li>
1079 * </ul>
1080 */
1081 boolean canReceive( final Bundle bundle, final String location )
1082 {
1083 if ( location == null )
1084 {
1085 return true;
1086 }
1087 else if ( location.startsWith( "?" ) )
1088 {
1089 // multi-location
1090 if ( System.getSecurityManager() != null )
1091 {
1092 return bundle.hasPermission( new ConfigurationPermission( location, ConfigurationPermission.TARGET ) );
1093 }
1094 return true;
1095 }
1096 else
1097 {
1098 // single location, must match
1099 return location.equals( bundle.getLocation() );
1100 }
1101 }
1102
1103 // ---------- inner classes
1104
1105 private ServiceHelper createServiceHelper( ConfigurationImpl config )
1106 {
1107 if ( config.getFactoryPid() == null )
1108 {
1109 return new ManagedServiceHelper( config );
1110 }
1111 return new ManagedServiceFactoryHelper( config );
1112 }
1113
1114 private abstract class ServiceHelper
1115 {
1116 protected final ConfigurationImpl config;
1117
1118 private final Dictionary properties;
1119
1120 protected ServiceHelper( ConfigurationImpl config )
1121 {
1122 this.config = config;
1123 this.properties = config.getProperties( true );
1124 }
1125
1126 final ServiceReference[] getServices( )
1127 {
1128 try
1129 {
1130 ServiceReference[] refs = doGetServices();
1131 if ( refs != null && refs.length > 1 )
1132 {
1133 Arrays.sort( refs, RankingComparator.SRV_RANKING );
1134 }
1135 return refs;
1136 }
1137 catch ( InvalidSyntaxException ise )
1138 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001139 log( LogService.LOG_ERROR, "Service selection filter is invalid to update {0}", new Object[]
1140 { config, ise } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001141 }
1142 return null;
1143 }
1144
1145
1146 protected abstract ServiceReference[] doGetServices() throws InvalidSyntaxException;
1147
1148
1149 abstract void provide( ServiceReference service );
1150
1151
1152 abstract void remove( ServiceReference service );
1153
1154
1155 protected Dictionary getProperties( String targetPid, ServiceReference service )
1156 {
1157 Dictionary props = new CaseInsensitiveDictionary( this.properties );
1158 callPlugins( props, targetPid, service, config );
1159 return props;
1160 }
1161 }
1162
1163 private class ManagedServiceHelper extends ServiceHelper
1164 {
1165
1166 protected ManagedServiceHelper( ConfigurationImpl config )
1167 {
1168 super( config );
1169 }
1170
1171
1172 public ServiceReference[] doGetServices() throws InvalidSyntaxException
1173 {
1174 return bundleContext.getServiceReferences( ManagedService.class.getName(), "(" + Constants.SERVICE_PID
1175 + "=" + config.getPid() + ")" );
1176 }
1177
1178
1179 public void provide( ServiceReference service )
1180 {
1181 ManagedService srv = ( ManagedService ) bundleContext.getService( service );
1182 if ( srv != null )
1183 {
1184 try
1185 {
1186 Dictionary props = getProperties( this.config.getPid(), service );
1187 srv.updated( props );
1188 }
1189 catch ( Throwable t )
1190 {
1191 handleCallBackError( t, service, config );
1192 }
1193 finally
1194 {
1195 bundleContext.ungetService( service );
1196 }
1197 }
1198 }
1199
1200
1201 public void remove( ServiceReference service )
1202 {
1203 ManagedService srv = ( ManagedService ) bundleContext.getService( service );
1204 try
1205 {
1206 srv.updated( null );
1207 }
1208 catch ( Throwable t )
1209 {
1210 handleCallBackError( t, service, config );
1211 }
1212 finally
1213 {
1214 bundleContext.ungetService( service );
1215 }
1216 }
1217
1218 }
1219
1220 private class ManagedServiceFactoryHelper extends ServiceHelper
1221 {
1222
1223 protected ManagedServiceFactoryHelper( ConfigurationImpl config )
1224 {
1225 super( config );
1226 // TODO Auto-generated constructor stub
1227 }
1228
1229
1230 public ServiceReference[] doGetServices() throws InvalidSyntaxException
1231 {
1232 return bundleContext.getServiceReferences( ManagedServiceFactory.class.getName(), "("
1233 + Constants.SERVICE_PID + "=" + config.getFactoryPid() + ")" );
1234 }
1235
1236
1237 public void provide( ServiceReference service )
1238 {
1239 ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext.getService( service );
1240 if ( srv != null )
1241 {
1242 try
1243 {
1244 Dictionary props = getProperties( this.config.getFactoryPid(), service );
1245 srv.updated( config.getPid(), props );
1246 }
1247 catch ( Throwable t )
1248 {
1249 handleCallBackError( t, service, config );
1250 }
1251 finally
1252 {
1253 bundleContext.ungetService( service );
1254 }
1255 }
1256 }
1257
1258
1259 public void remove( ServiceReference service )
1260 {
1261 ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext.getService( service );
1262 try
1263 {
1264 srv.deleted( config.getPid() );
1265 }
1266 catch ( Throwable t )
1267 {
1268 handleCallBackError( t, service, config );
1269 }
1270 finally
1271 {
1272 bundleContext.ungetService( service );
1273 }
1274 }
1275
1276 }
1277
1278 /**
1279 * The <code>ManagedServiceUpdate</code> updates a freshly registered
1280 * <code>ManagedService</code> with a specific configuration. If a
1281 * ManagedService is registered with multiple PIDs an instance of this
1282 * class is used for each registered PID.
1283 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001284 private class ManagedServiceUpdate implements Runnable
1285 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001286 private final String pid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001287
Felix Meschberger41cce522009-08-19 05:54:40 +00001288 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001289
Felix Meschberger41cce522009-08-19 05:54:40 +00001290 private final ManagedService service;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001291
Felix Meschberger41cce522009-08-19 05:54:40 +00001292 private final ConfigurationImpl config;
1293
1294 private final Dictionary rawProperties;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001295
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001296 private final long lastModificationTime;
1297
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001298 ManagedServiceUpdate( String pid, ServiceReference sr, ManagedService service )
1299 {
1300 this.pid = pid;
1301 this.sr = sr;
1302 this.service = service;
Felix Meschberger41cce522009-08-19 05:54:40 +00001303
1304 // get or load configuration for the pid
1305 ConfigurationImpl config = null;
1306 Dictionary rawProperties = null;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001307 long lastModificationTime = -1;
Felix Meschberger41cce522009-08-19 05:54:40 +00001308 try
1309 {
1310 config = getExistingConfiguration( pid );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001311 if ( config != null )
1312 {
1313 synchronized ( config )
1314 {
1315 rawProperties = config.getProperties( true );
1316 lastModificationTime = config.getLastModificationTime();
1317 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001318 }
1319 }
1320 catch ( IOException ioe )
1321 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001322 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1323 { pid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001324 }
1325
1326 this.config = config;
1327 this.rawProperties = rawProperties;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001328 this.lastModificationTime = lastModificationTime;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001329 }
1330
1331
1332 public void run()
1333 {
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001334 // only update configuration if lastModificationTime is less than
1335 // lastUpdateTime
Felix Meschberger41cce522009-08-19 05:54:40 +00001336 Dictionary properties = rawProperties;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001337 if ( properties != null && config != null && lastModificationTime < config.getLastUpdatedTime() )
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001338 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001339 log(
1340 LogService.LOG_DEBUG,
1341 "Configuration {0} at modification #{1} has already been updated to update #{2}, nothing to be done anymore.",
1342 new Object[]
1343 { config.getPid(), new Long( config.getLastModificationTime() ),
1344 new Long( config.getLastUpdatedTime() ) } );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001345 return;
1346 }
1347
1348 // check configuration and call plugins if existing
Felix Meschberger41cce522009-08-19 05:54:40 +00001349 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001350 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001351 log( LogService.LOG_DEBUG, "Updating configuration {0} to modification #{1}", new Object[]
1352 { pid, new Long( config.getLastModificationTime() ) } );
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001353
Felix Meschberger41243192009-01-14 19:59:58 +00001354 Bundle serviceBundle = sr.getBundle();
1355 if ( serviceBundle == null )
1356 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001357 log( LogService.LOG_INFO,
1358 "Service for PID {0} seems to already have been unregistered, not updating with configuration",
1359 new Object[]
1360 { pid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001361 return;
1362 }
1363
Felix Meschberger007c50e2011-10-20 12:39:38 +00001364 // CM 1.4 / 104.13.2.2
1365 if ( !canReceive( serviceBundle, config.getBundleLocation() ) )
Felix Meschberger2941ef92007-08-20 13:15:16 +00001366 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001367 log( LogService.LOG_ERROR,
Felix Meschberger4f269292011-10-21 13:52:31 +00001368 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1369 new Object[]
1370 { pid, ConfigurationManager.toString( sr ), config.getBundleLocation() } );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001371 return;
1372 }
1373
Felix Meschberger007c50e2011-10-20 12:39:38 +00001374 // 104.4.2 Dynamic Binding
1375 config.tryBindLocation( serviceBundle.getLocation() );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001376
1377 // prepare the configuration for the service (call plugins)
Felix Meschberger41cce522009-08-19 05:54:40 +00001378 callPlugins( properties, pid, sr, config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001379 }
1380 else
1381 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001382 // 104.5.3 ManagedService.updated must be called with null
1383 // if no configuration is available
Felix Meschberger41cce522009-08-19 05:54:40 +00001384 properties = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001385 }
1386
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001387 // update the service with the configuration
1388 try
1389 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001390 service.updated( properties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001391 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001392 catch ( Throwable t )
1393 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001394 handleCallBackError( t, sr, config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001395 }
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001396
1397 // update the lastUpdatedTime if there is configuration
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001398 if ( config != null && properties != null )
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001399 {
Felix Meschberger8d9851a2010-08-25 13:22:44 +00001400 config.setLastUpdatedTime( lastModificationTime );
Felix Meschberger4f269292011-10-21 13:52:31 +00001401 log( LogService.LOG_DEBUG, "Updated configuration {0} to update #{1}", new Object[]
1402 { config.getPid(), new Long( config.getLastUpdatedTime() ) } );
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001403 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001404 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001405
Felix Meschberger432e3872008-03-07 14:58:57 +00001406 public String toString()
1407 {
1408 return "ManagedService Update: pid=" + pid;
1409 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001410 }
1411
Felix Meschberger007c50e2011-10-20 12:39:38 +00001412 /**
1413 * The <code>ManagedServiceFactoryUpdate</code> updates a freshly
1414 * registered <code>ManagedServiceFactory</code> with a specific
1415 * configuration. If a ManagedServiceFactory is registered with
1416 * multiple PIDs an instance of this class is used for each registered
1417 * PID.
1418 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001419 private class ManagedServiceFactoryUpdate implements Runnable
1420 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001421 private final String factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001422
Felix Meschberger41cce522009-08-19 05:54:40 +00001423 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001424
Felix Meschberger41cce522009-08-19 05:54:40 +00001425 private final ManagedServiceFactory service;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001426
Felix Meschberger41cce522009-08-19 05:54:40 +00001427 private final Map configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001428
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001429 private final Map stamps;
1430
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001431 ManagedServiceFactoryUpdate( String factoryPid, ServiceReference sr, ManagedServiceFactory service )
1432 {
1433 this.factoryPid = factoryPid;
1434 this.sr = sr;
1435 this.service = service;
Felix Meschberger41cce522009-08-19 05:54:40 +00001436
1437 Factory factory = null;
1438 Map configs = null;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001439 Map stamps = null;
Felix Meschberger41cce522009-08-19 05:54:40 +00001440 try
1441 {
1442 factory = getFactory( factoryPid );
1443 if (factory != null) {
1444 configs = new HashMap();
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001445 stamps = new HashMap();
Felix Meschberger41cce522009-08-19 05:54:40 +00001446 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
1447 {
1448 final String pid = ( String ) pi.next();
1449 ConfigurationImpl cfg;
1450 try
1451 {
1452 cfg = getExistingConfiguration( pid );
1453 }
1454 catch ( IOException ioe )
1455 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001456 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1457 { pid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001458 continue;
1459 }
1460
1461 // sanity check on the configuration
1462 if ( cfg == null )
1463 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001464 log( LogService.LOG_ERROR, "Configuration {0} referred to by factory {1} does not exist",
1465 new Object[]
1466 { pid, factoryPid } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001467 factory.removePID( pid );
1468 factory.storeSilently();
1469 continue;
1470 }
1471 else if ( cfg.isNew() )
1472 {
1473 // Configuration has just been created but not yet updated
1474 // we currently just ignore it and have the update mechanism
1475 // provide the configuration to the ManagedServiceFactory
1476 // As of FELIX-612 (not storing new factory configurations)
1477 // this should not happen. We keep this for added stability
1478 // but raise the logging level to error.
Felix Meschberger4f269292011-10-21 13:52:31 +00001479 log( LogService.LOG_ERROR, "Ignoring new configuration pid={0}", new Object[]
1480 { pid } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001481 continue;
1482 }
1483 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1484 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001485 log( LogService.LOG_ERROR,
1486 "Configuration {0} referred to by factory {1} seems to belong to factory {2}",
1487 new Object[]
1488 { pid, factoryPid, cfg.getFactoryPid() } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001489 factory.removePID( pid );
1490 factory.storeSilently();
1491 continue;
1492 }
1493
1494 // get the configuration properties for later
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001495 synchronized ( cfg )
1496 {
1497 configs.put( cfg, cfg.getProperties( true ) );
1498 stamps.put( cfg, new Long( cfg.getLastModificationTime() ) );
1499 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001500 }
1501 }
1502 }
1503 catch ( IOException ioe )
1504 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001505 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID {0}", new Object[]
1506 { factoryPid, ioe } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001507 }
1508
Felix Meschberger41cce522009-08-19 05:54:40 +00001509 this.configs = configs;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001510 this.stamps = stamps;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001511 }
1512
1513
1514 public void run()
1515 {
Felix Meschberger41243192009-01-14 19:59:58 +00001516 Bundle serviceBundle = sr.getBundle();
1517 if ( serviceBundle == null )
1518 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001519 log(
1520 LogService.LOG_INFO,
1521 "ManagedServiceFactory for factory PID {0} seems to already have been unregistered, not updating with factory",
1522 new Object[]
1523 { factoryPid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001524 return;
1525 }
1526
Felix Meschberger41cce522009-08-19 05:54:40 +00001527 for ( Iterator ci=configs.entrySet().iterator(); ci.hasNext(); )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001528 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001529 final Map.Entry entry = (Map.Entry) ci.next();
1530 final ConfigurationImpl cfg = (ConfigurationImpl) entry.getKey();
1531 final Dictionary properties = (Dictionary) entry.getValue();
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001532 final long lastModificationTime = ( ( Long ) stamps.get( cfg ) ).longValue();
1533
Felix Meschberger007c50e2011-10-20 12:39:38 +00001534 if ( lastModificationTime <= cfg.getLastUpdatedTime() )
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001535 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001536 log(
1537 LogService.LOG_DEBUG,
1538 "Configuration {0} at modification #{1} has already been updated to update #{2}, nothing to be done anymore.",
1539 new Object[]
1540 { cfg.getPid(), new Long( cfg.getLastModificationTime() ),
1541 new Long( cfg.getLastUpdatedTime() ) } );
1542 continue;
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001543 }
1544
Felix Meschberger4f269292011-10-21 13:52:31 +00001545 log( LogService.LOG_DEBUG, "Updating configuration {0} to modification #{1}", new Object[]
1546 { cfg.getPid(), new Long( cfg.getLastModificationTime() ) } );
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001547
Felix Meschberger007c50e2011-10-20 12:39:38 +00001548 // CM 1.4 / 104.13.2.1
1549 if ( !canReceive( serviceBundle, cfg.getBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001550 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001551 log( LogService.LOG_ERROR,
Felix Meschberger4f269292011-10-21 13:52:31 +00001552 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1553 new Object[]
1554 { cfg.getPid(), ConfigurationManager.toString( sr ), cfg.getBundleLocation() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001555 continue;
1556 }
1557
Felix Meschberger007c50e2011-10-20 12:39:38 +00001558 // 104.4.2 Dynamic Binding
1559 cfg.tryBindLocation( serviceBundle.getLocation() );
Felix Meschberger41cce522009-08-19 05:54:40 +00001560
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001561 // prepare the configuration for the service (call plugins)
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001562 // call the plugins with cm.target set to the service's factory PID
1563 // (clarification in Section 104.9.1 of Compendium 4.2)
Felix Meschberger41cce522009-08-19 05:54:40 +00001564 callPlugins( properties, factoryPid, sr, cfg );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001565
Felix Meschbergerce67d732009-08-20 06:26:35 +00001566 // update the service with the configuration (if non-null)
1567 if ( properties != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001568 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001569 log( LogService.LOG_DEBUG, "{0}: Updating configuration pid={1}", new Object[]
1570 { ConfigurationManager.toString( sr ), cfg.getPid() } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001571
Felix Meschbergerce67d732009-08-20 06:26:35 +00001572 try
Felix Meschberger2941ef92007-08-20 13:15:16 +00001573 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001574 service.updated( cfg.getPid(), properties );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001575 }
Felix Meschbergerce67d732009-08-20 06:26:35 +00001576 catch ( Throwable t )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001577 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001578 handleCallBackError( t, sr, cfg );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001579 }
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001580
1581 // update the lastUpdatedTime
Felix Meschberger8d9851a2010-08-25 13:22:44 +00001582 cfg.setLastUpdatedTime( lastModificationTime );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001583
Felix Meschberger4f269292011-10-21 13:52:31 +00001584 log( LogService.LOG_DEBUG, "Updated configuration {0} to update #{1}", new Object[]
1585 { cfg.getPid(), new Long( cfg.getLastUpdatedTime() ) } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001586 }
1587 }
1588 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001589
1590
Felix Meschberger432e3872008-03-07 14:58:57 +00001591 public String toString()
1592 {
1593 return "ManagedServiceFactory Update: factoryPid=" + factoryPid;
1594 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001595 }
1596
Felix Meschberger007c50e2011-10-20 12:39:38 +00001597
1598 /**
1599 * The <code>UpdateConfiguration</code> is used to update
1600 * <code>ManagedService[Factory]</code> services with the configuration
1601 * they are subscribed to. This may cause the configuration to be
1602 * supplied to multiple services.
1603 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001604 private class UpdateConfiguration implements Runnable
1605 {
1606
Felix Meschberger41cce522009-08-19 05:54:40 +00001607 private final ConfigurationImpl config;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001608 private final ServiceHelper helper;
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001609 private final long lastModificationTime;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001610
1611
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001612 UpdateConfiguration( final ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001613 {
1614 this.config = config;
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001615 synchronized ( config )
1616 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001617 this.helper = createServiceHelper( config );
Felix Meschbergerfd52e312009-08-29 19:44:58 +00001618 this.lastModificationTime = config.getLastModificationTime();
1619 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001620 }
1621
1622
1623 public void run()
1624 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001625 if ( lastModificationTime <= config.getLastUpdatedTime() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001626 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001627 log(
1628 LogService.LOG_DEBUG,
1629 "Configuration {0} at modification #{1} has already been updated to update #{2}, nothing to be done anymore.",
1630 new Object[]
1631 { config.getPid(), new Long( config.getLastModificationTime() ),
1632 new Long( config.getLastUpdatedTime() ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001633 return;
1634 }
1635
Felix Meschberger4f269292011-10-21 13:52:31 +00001636 log( LogService.LOG_DEBUG, "Updating configuration {0} to modification #{1}", new Object[]
1637 { config.getPid(), new Long( config.getLastModificationTime() ) } );
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001638
Felix Meschberger007c50e2011-10-20 12:39:38 +00001639 final ServiceReference[] srList = helper.getServices();
1640 if ( srList != null )
Felix Meschberger41cce522009-08-19 05:54:40 +00001641 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001642 // optionally bind dynamically to the first service
1643 config.tryBindLocation( srList[0].getBundle().getLocation() );
1644
1645 final String configBundleLocation = config.getBundleLocation();
1646
1647 // provide configuration to all services from the
1648 // correct bundle
Felix Meschberger41cce522009-08-19 05:54:40 +00001649 for ( int i = 0; i < srList.length; i++ )
1650 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001651 final ServiceReference ref = srList[i];
1652
1653 // CM 1.4 / 104.13.2.2
1654 if ( !canReceive( ref.getBundle(), configBundleLocation ) )
Felix Meschberger41cce522009-08-19 05:54:40 +00001655 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001656 log( LogService.LOG_ERROR,
1657 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1658 new Object[]
1659 { config.getPid(), ConfigurationManager.toString( ref ), configBundleLocation } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001660 continue;
1661 }
1662
1663 helper.provide( ref );
1664
Felix Meschberger4f269292011-10-21 13:52:31 +00001665 log( LogService.LOG_DEBUG, "Updated configuration {0} to update #{1}", new Object[]
1666 { config.getPid(), new Long( config.getLastUpdatedTime() ) } );
Felix Meschberger41cce522009-08-19 05:54:40 +00001667 }
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001668
Felix Meschberger007c50e2011-10-20 12:39:38 +00001669 // update the lastUpdatedTime
1670 config.setLastUpdatedTime( lastModificationTime );
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001671 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001672 }
1673
1674
Felix Meschberger432e3872008-03-07 14:58:57 +00001675 public String toString()
1676 {
1677 return "Update: pid=" + config.getPid();
1678 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001679 }
1680
Felix Meschberger007c50e2011-10-20 12:39:38 +00001681
1682 /**
1683 * The <code>DeleteConfiguration</code> class is used to inform
1684 * <code>ManagedService[Factory]</code> services of a configuration
1685 * being deleted.
1686 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001687 private class DeleteConfiguration implements Runnable
1688 {
Felix Meschberger66423332007-08-22 08:46:34 +00001689
Felix Meschbergerce67d732009-08-20 06:26:35 +00001690 private final ConfigurationImpl config;
Felix Meschbergerc12db8c2009-08-19 06:43:59 +00001691 private final String configLocation;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001692
1693
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001694 DeleteConfiguration( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001695 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001696 /*
1697 * NOTE: We keep the configuration because it might be cleared just
1698 * after calling this method. The pid and factoryPid fields are
1699 * final and cannot be reset.
1700 */
1701 this.config = config;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001702 this.configLocation = config.getBundleLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001703 }
1704
1705
1706 public void run()
1707 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001708 final String pid = config.getPid();
1709 final String factoryPid = config.getFactoryPid();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001710 final ServiceHelper helper = createServiceHelper( config );
Felix Meschbergerce67d732009-08-20 06:26:35 +00001711
Felix Meschberger007c50e2011-10-20 12:39:38 +00001712 ServiceReference[] srList = helper.getServices( );
1713 if ( srList != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001714 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001715 for ( int i = 0; i < srList.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001716 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001717 final ServiceReference sr = srList[i];
1718 if ( canReceive( sr.getBundle(), configLocation ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001719 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001720 helper.remove( sr );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001721 }
1722 }
1723 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001724
1725 if ( factoryPid != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001726 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001727 // remove the pid from the factory
1728 try
1729 {
1730 Factory factory = getFactory( factoryPid );
1731 factory.removePID( pid );
1732 factory.store();
1733 }
1734 catch ( IOException ioe )
1735 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001736 log( LogService.LOG_ERROR, "Failed removing {0} from the factory {1}", new Object[]
1737 { pid, factoryPid, ioe } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001738 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001739 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001740 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001741
Felix Meschberger432e3872008-03-07 14:58:57 +00001742 public String toString()
1743 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001744 return "Delete: pid=" + config.getPid();
Felix Meschberger432e3872008-03-07 14:58:57 +00001745 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001746 }
1747
Felix Meschberger007c50e2011-10-20 12:39:38 +00001748 private class LocationChanged implements Runnable
1749 {
1750 private final ConfigurationImpl config;
1751 private final String oldLocation;
1752
1753
1754 LocationChanged( ConfigurationImpl config, String oldLocation )
1755 {
1756 this.config = config;
1757 this.oldLocation = oldLocation;
1758 }
1759
1760
1761 public void run()
1762 {
1763 ServiceHelper helper = createServiceHelper( this.config );
1764 ServiceReference[] srList = helper.getServices( );
1765 if ( srList != null )
1766 {
1767 // make sure the config is dynamically bound to the first
1768 // service if it has been unbound causing this update
1769 config.tryBindLocation( srList[0].getBundle().getLocation() );
1770
1771 for ( int i = 0; i < srList.length; i++ )
1772 {
1773 final ServiceReference sr = srList[i];
1774 final boolean wasVisible = canReceive( sr.getBundle(), oldLocation );
1775 final boolean isVisible = canReceive( sr.getBundle(), config.getBundleLocation() );
1776 if ( wasVisible && !isVisible )
1777 {
1778 // call deleted method
1779 helper.remove( sr );
Felix Meschberger4f269292011-10-21 13:52:31 +00001780 log( LogService.LOG_DEBUG, "Configuration {0} revoked from {1} (no more visibility)",
1781 new Object[]
1782 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001783 }
1784 else if ( !wasVisible && isVisible )
1785 {
1786 // call updated method
1787 helper.provide( sr );
Felix Meschberger4f269292011-10-21 13:52:31 +00001788 log( LogService.LOG_DEBUG, "Configuration {0} provided to {1} (new visibility)", new Object[]
1789 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger35658d52011-10-20 21:43:58 +00001790 }
Felix Meschberger4f269292011-10-21 13:52:31 +00001791 else
Felix Meschberger35658d52011-10-20 21:43:58 +00001792 {
1793 // same visibility as before
Felix Meschberger4f269292011-10-21 13:52:31 +00001794 log( LogService.LOG_DEBUG, "Unmodified visibility to configuration {0} for {1}", new Object[]
1795 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001796 }
1797 }
1798 }
1799 }
1800
1801
1802 public String toString()
1803 {
1804 return "Location Changed (pid=" + config.getPid() + "): " + oldLocation + " ==> "
1805 + config.getBundleLocation();
1806 }
1807 }
1808
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001809 private class FireConfigurationEvent implements Runnable
1810 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001811 private final int type;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001812
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001813 private final String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001814
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001815 private final String factoryPid;
1816
1817 private final ServiceReference[] listenerReferences;
1818
1819 private final ConfigurationListener[] listeners;
1820
1821 private final Bundle[] listenerProvider;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001822
1823
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001824 private FireConfigurationEvent( final int type, final String pid, final String factoryPid)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001825 {
1826 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001827 this.pid = pid;
1828 this.factoryPid = factoryPid;
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001829
1830 final ServiceReference[] srs = configurationListenerTracker.getServiceReferences();
1831 if ( srs == null || srs.length == 0 )
1832 {
1833 this.listenerReferences = null;
1834 this.listeners = null;
1835 this.listenerProvider = null;
1836 }
1837 else
1838 {
1839 this.listenerReferences = srs;
1840 this.listeners = new ConfigurationListener[srs.length];
1841 this.listenerProvider = new Bundle[srs.length];
1842 for ( int i = 0; i < srs.length; i++ )
1843 {
1844 this.listeners[i] = ( ConfigurationListener ) configurationListenerTracker.getService( srs[i] );
1845 this.listenerProvider[i] = srs[i].getBundle();
1846 }
1847 }
1848 }
1849
1850
1851 boolean hasConfigurationEventListeners()
1852 {
1853 return this.listenerReferences != null;
1854 }
1855
1856
1857 String getTypeName()
1858 {
1859 switch ( type )
1860 {
1861 case ConfigurationEvent.CM_DELETED:
1862 return "CM_DELETED";
1863 case ConfigurationEvent.CM_UPDATED:
1864 return "CM_UPDATED";
Felix Meschberger007c50e2011-10-20 12:39:38 +00001865 case ConfigurationEvent.CM_LOCATION_CHANGED:
1866 return "CM_LOCATION_CHANGED";
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001867 default:
1868 return "<UNKNOWN(" + type + ")>";
1869 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001870 }
1871
1872
1873 public void run()
1874 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001875 final String typeName = getTypeName();
1876 final ConfigurationEvent event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001877
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001878 for ( int i = 0; i < listeners.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001879 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001880 if ( listenerProvider[i].getState() == Bundle.ACTIVE )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001881 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001882 log( LogService.LOG_DEBUG, "Sending {0} event for {1} to {2}", new Object[]
1883 { typeName, pid, ConfigurationManager.toString( listenerReferences[i] ) } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001884
1885 try
1886 {
1887 listeners[i].configurationEvent( event );
1888 }
1889 catch ( Throwable t )
1890 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001891 log( LogService.LOG_ERROR, "Unexpected problem delivering configuration event to {0}",
1892 new Object[]
1893 { ConfigurationManager.toString( listenerReferences[i] ), t } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001894 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001895 }
1896 }
1897 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001898
Felix Meschberger432e3872008-03-07 14:58:57 +00001899 public String toString()
1900 {
1901 return "Fire ConfigurationEvent: pid=" + pid;
1902 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001903 }
1904
Felix Meschberger41cce522009-08-19 05:54:40 +00001905 private static class ManagedServiceTracker extends ServiceTracker
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001906 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001907
Felix Meschberger41cce522009-08-19 05:54:40 +00001908 private final ConfigurationManager cm;
1909
1910
1911 ManagedServiceTracker( ConfigurationManager cm )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001912 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001913 super( cm.bundleContext, ManagedService.class.getName(), null );
Carsten Ziegeler41683982007-12-27 08:35:27 +00001914 this.cm = cm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001915 open();
1916 }
1917
1918
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001919 public Object addingService( ServiceReference reference )
1920 {
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001921 Object serviceObject = super.addingService( reference );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001922
1923 // configure the managed service
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001924 if ( serviceObject instanceof ManagedService )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001925 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001926 cm.configure(reference, ( ManagedService ) serviceObject);
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001927 }
1928 else
1929 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001930 cm.log( LogService.LOG_WARNING, "Service {0} is not a ManagedService", new Object[]
1931 { serviceObject } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001932 }
1933
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001934 return serviceObject;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001935 }
1936 }
1937
Felix Meschberger41cce522009-08-19 05:54:40 +00001938 private static class ManagedServiceFactoryTracker extends ServiceTracker
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001939 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001940 private final ConfigurationManager cm;
1941
1942
1943 ManagedServiceFactoryTracker( ConfigurationManager cm )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001944 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001945 super( cm.bundleContext, ManagedServiceFactory.class.getName(), null );
1946 this.cm = cm;
1947 open();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001948 }
1949
1950
1951 public Object addingService( ServiceReference reference )
1952 {
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001953 Object serviceObject = super.addingService( reference );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001954
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001955 // configure the managed service factory
1956 if ( serviceObject instanceof ManagedServiceFactory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001957 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001958 cm.configure( reference, ( ManagedServiceFactory ) serviceObject );
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001959 }
1960 else
1961 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001962 cm.log( LogService.LOG_WARNING, "Service {0} is not a ManagedServiceFactory", new Object[]
1963 { serviceObject } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001964 }
1965
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001966 return serviceObject;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001967 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001968 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001969
1970
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001971}