blob: 064478005ecc5f4658860fff9dab55be41fb764b [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;
Carsten Ziegeler41683982007-12-27 08:35:27 +000024import java.util.*;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000025
26import org.apache.felix.cm.PersistenceManager;
27import org.apache.felix.cm.file.FilePersistenceManager;
Carsten Ziegeler41683982007-12-27 08:35:27 +000028import org.osgi.framework.*;
29import org.osgi.service.cm.*;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000030import org.osgi.service.log.LogService;
31import org.osgi.util.tracker.ServiceTracker;
32
33
34/**
35 * The <code>ConfigurationManager</code> is the central class in this
36 * implementation of the Configuration Admin Service Specification. As such it
37 * has the following tasks:
38 * <ul>
39 * <li>It is a <code>BundleActivator</code> which is called when the bundle
40 * is started and stopped.
41 * <li>It is a <code>BundleListener</code> which gets informed when the
42 * states of bundles change. Mostly this is needed to unbind any bound
43 * configuration in case a bundle is uninstalled.
44 * <li>It is a <code>ServiceListener</code> which gets informed when
45 * <code>ManagedService</code> and <code>ManagedServiceFactory</code>
46 * services are registered and unregistered. This is used to provide
47 * configuration to these services. As a service listener it also listens for
48 * {@link PersistenceManager} instances being registered to support different
49 * configuration persistence layers.
50 * <li>A {@link ConfigurationAdminFactory} instance is registered as the
51 * <code>ConfigurationAdmin</code> service.
52 * <li>A {@link FilePersistenceManager} instance is registered as a default
53 * {@link PersistenceManager}.
54 * <li>Last but not least this instance manages all tasks laid out in the
55 * specification such as maintaining configuration, taking care of configuration
56 * events, etc.
57 * </ul>
58 * <p>
59 * The default {@link FilePersistenceManager} is configured with a configuration
60 * location taken from the <code>felix.cm.dir</code> framework property. If
61 * this property is not set the <code>config</code> directory in the current
62 * working directory as specified in the <code>user.dir</code> system property
63 * is used.
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000064 */
65public class ConfigurationManager implements BundleActivator, BundleListener
66{
67
68 /**
69 * The name of the bundle context property defining the location for the
70 * configuration files (value is "felix.cm.dir").
Felix Meschberger2fd5b582007-12-10 10:32:29 +000071 *
Carsten Ziegeler7853b9a2008-01-11 16:30:24 +000072 * @see #start(BundleContext)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000073 */
74 public static final String CM_CONFIG_DIR = "felix.cm.dir";
75
Felix Meschberger08282c32009-01-28 07:01:55 +000076 /**
77 * The name of the bundle context property defining the maximum log level
78 * (value is "felix.cm.loglevel"). The log level setting is only used if
79 * there is no OSGi LogService available. Otherwise this setting is ignored.
80 * <p>
81 * This value of this property is expected to be an integer number
82 * corresponding to the log level values of the OSGi LogService. That is 1
83 * for errors, 2 for warnings, 3 for informational messages and 4 for debug
84 * messages. The default value is 2, such that only warnings and errors are
85 * logged in the absence of a LogService.
86 */
87 public static final String CM_LOG_LEVEL = "felix.cm.loglevel";
88
Felix Meschberger85b355d2007-08-31 07:17:38 +000089 // The name of the LogService (not using the class, which might be missing)
90 private static final String LOG_SERVICE_NAME = "org.osgi.service.log.LogService";
Felix Meschberger2fd5b582007-12-10 10:32:29 +000091
Felix Meschberger08282c32009-01-28 07:01:55 +000092 private static final int CM_LOG_LEVEL_DEFAULT = 2;
Felix Meschberger5dfaa962009-08-14 19:26:01 +000093
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000094 // random number generator to create configuration PIDs for factory
95 // configurations
96 private static SecureRandom numberGenerator;
97
98 // comparator used to keep the ordered persistence manager map
99 private static final Comparator cmRankComp = new RankingComparator( true, ConfigurationPlugin.CM_RANKING );
100
101 // the BundleContext of the Configuration Admin Service bundle
102 private BundleContext bundleContext;
103
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000104 // the service registration of the configuration admin
105 private ServiceRegistration configurationAdminRegistration;
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000106
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000107 // the ServiceTracker to emit log services (see log(int, String, Throwable))
108 private ServiceTracker logTracker;
109
110 // the ConfigurationEvent listeners
111 private ServiceTracker configurationListenerTracker;
112
113 // service tracker for managed services
114 private ServiceTracker managedServiceTracker;
115
116 // service tracker for managed service factories
117 private ServiceTracker managedServiceFactoryTracker;
118
119 // PersistenceManager services
120 private ServiceTracker persistenceManagerTracker;
121
122 // the thread used to schedule tasks required to run asynchronously
123 private UpdateThread updateThread;
124
125 /**
126 * The actual list of {@link PersistenceManager persistence managers} to use
127 * when looking for configuration data. This list is built from the
128 * {@link #persistenceManagerMap}, which is ordered according to the
129 * {@link RankingComparator}.
130 */
131 private PersistenceManager[] persistenceManagers;
132
133 // the persistenceManagerTracker.getTrackingCount when the
134 // persistenceManagers were last got
135 private int pmtCount;
136
137 // the cache of Factory instances mapped by their factory PID
Felix Meschberger6a698df2009-08-16 18:38:46 +0000138 private final Map factories = new HashMap();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000139
140 // the cache of Configuration instances mapped by their PID
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000141 // have this always set to prevent NPE on bundle shutdown
142 private final Map configurations = new HashMap();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000143
Felix Meschberger08282c32009-01-28 07:01:55 +0000144 // the maximum log level when no LogService is available
145 private int logLevel = CM_LOG_LEVEL_DEFAULT;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000146
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000147 // flag indicating whether BundleChange events should be consumed (FELIX-979)
148 private volatile boolean handleBundleEvents;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000149
150 public void start( BundleContext bundleContext )
151 {
152 // track the log service using a ServiceTracker
Felix Meschberger85b355d2007-08-31 07:17:38 +0000153 logTracker = new ServiceTracker( bundleContext, LOG_SERVICE_NAME , null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000154 logTracker.open();
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000155
Felix Meschberger08282c32009-01-28 07:01:55 +0000156 // assign the log level
157 String logLevelProp = bundleContext.getProperty( CM_LOG_LEVEL );
158 if ( logLevelProp == null )
159 {
160 logLevel = CM_LOG_LEVEL_DEFAULT;
161 }
162 else
163 {
164 try
165 {
166 logLevel = Integer.parseInt( logLevelProp );
167 }
168 catch ( NumberFormatException nfe )
169 {
170 logLevel = CM_LOG_LEVEL_DEFAULT;
171 }
172 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000173
174 // set up some fields
175 this.bundleContext = bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000176
177 // configurationlistener support
178 configurationListenerTracker = new ServiceTracker( bundleContext, ConfigurationListener.class.getName(), null );
179 configurationListenerTracker.open();
180
181 // initialize the asynchonous updater thread
182 this.updateThread = new UpdateThread( this );
183 this.updateThread.start();
184
185 // set up the location (might throw IllegalArgumentException)
186 try
187 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000188 FilePersistenceManager fpm = new FilePersistenceManager( bundleContext, bundleContext
189 .getProperty( CM_CONFIG_DIR ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000190 Hashtable props = new Hashtable();
191 props.put( Constants.SERVICE_PID, fpm.getClass().getName() );
192 props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
193 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
194 props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
195 bundleContext.registerService( PersistenceManager.class.getName(), fpm, props );
196 }
197 catch ( IllegalArgumentException iae )
198 {
199 log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
200 }
201
202 // register as bundle and service listener
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000203 handleBundleEvents = true;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000204 bundleContext.addBundleListener( this );
205
206 // get all persistence managers to begin with
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000207 pmtCount = 1; // make sure to get the persistence managers at least once
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000208 persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
209 persistenceManagerTracker.open();
210
211 // create and register configuration admin - start after PM tracker ...
212 ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
213 Hashtable props = new Hashtable();
214 props.put( Constants.SERVICE_PID, "org.apache.felix.cm.ConfigurationAdmin" );
215 props.put( Constants.SERVICE_DESCRIPTION, "Configuration Admin Service Specification 1.2 Implementation" );
216 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000217 configurationAdminRegistration = bundleContext.registerService( ConfigurationAdmin.class.getName(), caf, props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000218
219 // start handling ManagedService[Factory] services
Carsten Ziegeler41683982007-12-27 08:35:27 +0000220 managedServiceTracker = new ManagedServiceTracker(this);
221 managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this);
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000222 }
223
224
225 public void stop( BundleContext bundleContext )
226 {
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000227
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000228 // stop handling bundle events immediately
229 handleBundleEvents = false;
230
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000231 // immediately unregister the Configuration Admin before cleaning up
Felix Meschberger10568352009-01-15 08:57:11 +0000232 // clearing the field before actually unregistering the service
233 // prevents IllegalStateException in getServiceReference() if
234 // the field is not null but the service already unregistered
235 if (configurationAdminRegistration != null) {
236 ServiceRegistration reg = configurationAdminRegistration;
237 configurationAdminRegistration = null;
238 reg.unregister();
239 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000240
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000241 // stop handling ManagedService[Factory] services
242 managedServiceFactoryTracker.close();
243 managedServiceTracker.close();
244
245 // don't care for PersistenceManagers any more
246 persistenceManagerTracker.close();
247
248 // stop listening for events
249 bundleContext.removeBundleListener( this );
250
251 if ( configurationListenerTracker != null )
252 {
253 configurationListenerTracker.close();
254 }
255
256 if ( updateThread != null )
257 {
258 // terminate asynchrounous updates
259 updateThread.terminate();
260
261 // wait for all updates to terminate
262 try
263 {
264 updateThread.join();
265 }
266 catch ( InterruptedException ie )
267 {
268 // don't really care
269 }
270 }
271
272 if ( logTracker != null )
273 {
274 logTracker.close();
275 }
276
Felix Meschberger6a698df2009-08-16 18:38:46 +0000277 // just ensure the configuration cache is empty
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000278 synchronized ( configurations )
279 {
280 configurations.clear();
281 }
282
Felix Meschberger6a698df2009-08-16 18:38:46 +0000283 // just ensure the factory cache is empty
284 synchronized ( factories )
285 {
286 factories.clear();
287 }
288
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000289 this.bundleContext = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000290 }
291
292
293 // ---------- Configuration caching support --------------------------------
294
295 ConfigurationImpl getCachedConfiguration( String pid )
296 {
297 synchronized ( configurations )
298 {
299 return ( ConfigurationImpl ) configurations.get( pid );
300 }
301 }
302
303
Felix Meschberger6a698df2009-08-16 18:38:46 +0000304 ConfigurationImpl[] getCachedConfigurations()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000305 {
306 synchronized ( configurations )
307 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000308 return ( ConfigurationImpl[] ) configurations.values().toArray(
309 new ConfigurationImpl[configurations.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000310 }
311 }
312
313
Felix Meschberger2941ef92007-08-20 13:15:16 +0000314 ConfigurationImpl cacheConfiguration( ConfigurationImpl configuration )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000315 {
316 synchronized ( configurations )
317 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000318 Object existing = configurations.get( configuration.getPid() );
319 if ( existing != null )
320 {
321 return ( ConfigurationImpl ) existing;
322 }
323
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000324 configurations.put( configuration.getPid(), configuration );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000325 return configuration;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000326 }
327 }
328
329
330 void removeConfiguration( ConfigurationImpl configuration )
331 {
332 synchronized ( configurations )
333 {
334 configurations.remove( configuration.getPid() );
335 }
336 }
337
338
Felix Meschberger6a698df2009-08-16 18:38:46 +0000339 Factory getCachedFactory( String factoryPid )
340 {
341 synchronized ( factories )
342 {
343 return ( Factory ) factories.get( factoryPid );
344 }
345 }
346
347
348 Factory[] getCachedFactories()
349 {
350 synchronized ( factories )
351 {
352 return ( Factory[] ) factories.values().toArray( new Factory[factories.size()] );
353 }
354 }
355
356
357 void cacheFactory( Factory factory )
358 {
359 synchronized ( factories )
360 {
361 factories.put( factory.getFactoryPid(), factory );
362 }
363 }
364
365
366
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000367 // ---------- ConfigurationAdminImpl support -------------------------------
368
369 /*
370 * (non-Javadoc)
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000371 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000372 * @see org.osgi.service.cm.ConfigurationAdmin#createFactoryConfiguration(java.lang.String)
373 */
374 ConfigurationImpl createFactoryConfiguration( ConfigurationAdminImpl configurationAdmin, String factoryPid )
375 throws IOException
376 {
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000377 // check Persmission if factory is bound to another bundle
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000378 Factory factory = getFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000379 if ( factory.getBundleLocation() != null
380 && !factory.getBundleLocation().equals( configurationAdmin.getBundle().getLocation() ) )
381 {
382 configurationAdmin.checkPermission();
383 }
384
385 // create the configuration
386 String pid = createPid( factoryPid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000387 ConfigurationImpl config = createConfiguration( pid, factoryPid, configurationAdmin.getBundle().getLocation() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000388
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000389 return config;
390 }
391
392
393 /*
394 * (non-Javadoc)
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000395 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000396 * @see org.osgi.service.cm.ConfigurationAdmin#createFactoryConfiguration(java.lang.String,
397 * java.lang.String)
398 */
399 ConfigurationImpl createFactoryConfiguration( String factoryPid, String location ) throws IOException
400 {
401 // create the configuration
402 String pid = createPid( factoryPid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000403 ConfigurationImpl config = createConfiguration( pid, factoryPid, location );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000404
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000405 return config;
406 }
407
408
Felix Meschberger2941ef92007-08-20 13:15:16 +0000409 ConfigurationImpl getExistingConfiguration( String pid ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000410 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000411 ConfigurationImpl config = getCachedConfiguration( pid );
412 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000413 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000414 return config;
415 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000416
Felix Meschberger2941ef92007-08-20 13:15:16 +0000417 PersistenceManager[] pmList = getPersistenceManagers();
418 for ( int i = 0; i < pmList.length; i++ )
419 {
420 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000421 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000422 Dictionary props = pmList[i].load( pid );
423 config = new ConfigurationImpl( this, pmList[i], props );
424 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000425 }
426 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000427
Felix Meschberger2941ef92007-08-20 13:15:16 +0000428 // neither the cache nor any persistence manager has configuration
429 return null;
430 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000431
432
Felix Meschberger2941ef92007-08-20 13:15:16 +0000433 ConfigurationImpl getConfiguration( String pid, String bundleLocation ) throws IOException
434 {
435 // check for existing (cached or persistent) configuration
436 ConfigurationImpl config = getExistingConfiguration( pid );
437 if ( config != null )
438 {
439 return config;
440 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000441
Felix Meschberger2941ef92007-08-20 13:15:16 +0000442 // else create new configuration also setting the bundle location
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000443 // and cache the new configuration
444 config = createConfiguration( pid, null, bundleLocation );
445 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000446 }
447
448
449 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
450 throws IOException, InvalidSyntaxException
451 {
452 Filter filter = null;
453 if ( filterString != null )
454 {
455 filter = bundleContext.createFilter( filterString );
456 }
457
458 boolean unprivileged = configurationAdmin != null && !configurationAdmin.hasPermission();
459 String location = unprivileged ? configurationAdmin.getBundle().getLocation() : null;
460
461 List configList = new ArrayList();
462
463 PersistenceManager[] pmList = getPersistenceManagers();
464 for ( int i = 0; i < pmList.length; i++ )
465 {
466 Enumeration configs = pmList[i].getDictionaries();
467 while ( configs.hasMoreElements() )
468 {
469 Dictionary config = ( Dictionary ) configs.nextElement();
470
471 // ignore non-Configuration dictionaries
Felix Meschberger86a0d172007-07-04 07:15:01 +0000472 String pid = ( String ) config.get( Constants.SERVICE_PID );
473 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000474 {
475 continue;
476 }
477
478 // ignore this config if not privileged and not bound to bundle
479 if ( unprivileged )
480 {
481 Object boundLocation = config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION );
482 if ( !location.equals( boundLocation ) )
483 {
484 continue;
485 }
486 }
487
488 // check filter
489 if ( filter == null || filter.match( config ) )
490 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000491 // ensure the service.pid and returned a cached config if available
492 ConfigurationImpl cfg = getCachedConfiguration( pid );
493 if ( cfg == null )
494 {
495 cfg = new ConfigurationImpl( this, pmList[i], config );
496 }
497
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000498 // FELIX-611: Ignore configuration objects without props
499 if ( !cfg.isNew() )
500 {
501 configList.add( cfg );
502 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000503 }
504 }
505 }
506
Felix Meschberger8faceff2007-07-04 07:19:48 +0000507 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000508 .size()] );
509 }
510
511
512 void deleted( ConfigurationImpl config )
513 {
514 // remove the configuration from the cache
515 removeConfiguration( config );
516 updateThread.schedule( new DeleteConfiguration( config ) );
517 }
518
519
520 void updated( ConfigurationImpl config )
521 {
522 updateThread.schedule( new UpdateConfiguration( config ) );
523 }
524
525
Felix Meschberger66423332007-08-22 08:46:34 +0000526 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000527 {
528
Felix Meschberger66423332007-08-22 08:46:34 +0000529 updateThread.schedule( new FireConfigurationEvent( type, pid, factoryPid) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000530 }
531
532
533 // ---------- BundleListener -----------------------------------------------
534
535 public void bundleChanged( BundleEvent event )
536 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000537 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000538 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000539 final String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000540
Felix Meschberger6a698df2009-08-16 18:38:46 +0000541 // we only reset dynamic bindings, which are only present in
542 // cached configurations, hence only consider cached configs here
543 final ConfigurationImpl[] configs = getCachedConfigurations();
544 for ( int i = 0; i < configs.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000545 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000546 final ConfigurationImpl cfg = configs[i];
547 if ( location.equals( cfg.getBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000548 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000549 // reset dynamic binding
550 cfg.setBundleLocation( null, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000551 }
552 }
Felix Meschberger6a698df2009-08-16 18:38:46 +0000553
554 // we only reset dynamic bindings, which are only present in
555 // cached factories, hence only consider cached factories here
556 final Factory[] factories = getCachedFactories();
557 for ( int i = 0; i < factories.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000558 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000559 final Factory factory = factories[i];
560 if ( location.equals( factory.getBundleLocation() ) )
561 {
562 // reset dynamic binding
563 factory.setBundleLocation( null, false );
564 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000565 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000566 }
567 }
568
569
570 // ---------- internal -----------------------------------------------------
571
572 private PersistenceManager[] getPersistenceManagers()
573 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000574 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
575 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000576 {
577
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000578 List pmList = new ArrayList();
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000579 PersistenceManager[] pm;
580
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000581 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
582 if ( refs == null || refs.length == 0 )
583 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000584 pm = new PersistenceManager[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000585 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000586 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000587 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000588 // sort the references according to the cmRanking property
589 SortedSet pms = new TreeSet( new RankingComparator( false ) );
590 for ( int i = 0; i < refs.length; i++ )
591 {
592 pms.add( refs[i] );
593 }
594
595 // create the service array from the sorted set of referenecs
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000596 int pmIndex = 0;
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000597 for ( Iterator pi = pms.iterator(); pi.hasNext(); pmIndex++ )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000598 {
599 ServiceReference ref = ( ServiceReference ) pi.next();
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000600 Object service = persistenceManagerTracker.getService( ref );
601 if ( service != null )
602 {
603 pmList.add( service );
604 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000605 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000606
607 pm = ( PersistenceManager[] ) pmList.toArray( new PersistenceManager[pmList.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000608 }
609
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000610 pmtCount = pm.length;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000611 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000612 }
613
614 return persistenceManagers;
615 }
616
617
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000618 private ServiceReference getServiceReference()
619 {
620 ServiceRegistration reg = configurationAdminRegistration;
621 return ( reg != null ) ? reg.getReference() : null;
622 }
623
624
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000625 private void configure( ServiceReference sr, ManagedService service )
626 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000627 String[] pids = getServicePid( sr );
628 if ( pids != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000629 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000630 for ( int i = 0; i < pids.length; i++ )
631 {
632 ManagedServiceUpdate update = new ManagedServiceUpdate( pids[i], sr, service );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000633 updateThread.schedule( update );
634 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000635 }
Felix Meschberger851c6412009-08-16 18:43:26 +0000636 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000637
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000638
639 private void configure( ServiceReference sr, ManagedServiceFactory service )
640 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000641 String[] pids = getServicePid( sr );
642 if ( pids != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000643 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000644 for ( int i = 0; i < pids.length; i++ )
645 {
646 ManagedServiceFactoryUpdate update = new ManagedServiceFactoryUpdate( pids[i], sr, service );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000647 updateThread.schedule( update );
648 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000649 }
Felix Meschberger851c6412009-08-16 18:43:26 +0000650 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000651
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000652
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000653 /**
654 * Factory method to create a new configuration object. The configuration
655 * object returned is not stored in configuration cache and only persisted
656 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000657 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000658 * @param pid
659 * The PID of the new configuration object. Must not be
660 * <code>null</code>.
661 * @param factoryPid
662 * The factory PID of the new configuration. Not
Felix Meschberger6a698df2009-08-16 18:38:46 +0000663 * <code>null</code> if the new configuration object belongs to a
664 * factory. The configuration object will not be persisted if
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000665 * this parameter is not <code>null</code>.
666 * @param bundleLocation
667 * The bundle location of the bundle to which the configuration
Felix Meschberger6a698df2009-08-16 18:38:46 +0000668 * belongs or <code>null</code> if the configuration is not bound
669 * yet.
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000670 * @return The new configuration object
671 * @throws IOException
672 * May be thrown if an error occurrs persisting the new
673 * configuration object.
674 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000675 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000676 {
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000677 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000678 }
679
680
681 Factory getFactory( String factoryPid ) throws IOException
682 {
Felix Meschbergerf4631322008-03-10 12:32:35 +0000683 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000684 if ( factory != null )
685 {
686 return factory;
687 }
688
689 PersistenceManager[] pmList = getPersistenceManagers();
690 for ( int i = 0; i < pmList.length; i++ )
691 {
692 if ( Factory.exists( pmList[i], factoryPid ) )
693 {
694 factory = Factory.load( pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000695 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000696 return factory;
697 }
698 }
699
700 // if getting here, there is no configuration yet, optionally create new
701 return createFactory( factoryPid );
702 }
703
704
705 Factory createFactory( String factoryPid )
706 {
707 Factory factory = new Factory( getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000708 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000709 return factory;
710 }
711
712
Felix Meschberger2941ef92007-08-20 13:15:16 +0000713 /**
714 * Calls the registered configuration plugins on the given configuration
715 * object unless the configuration has just been created and not been
716 * updated yet.
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000717 *
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000718 * @param targetPid The identification of the configuration update used to
719 * select the plugins according to their cm.target service
720 * property
Felix Meschberger2941ef92007-08-20 13:15:16 +0000721 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000722 * is to be updated with configuration
Felix Meschberger2941ef92007-08-20 13:15:16 +0000723 * @param cfg The configuration object whose properties have to be passed
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000724 * through the plugins
Felix Meschberger2941ef92007-08-20 13:15:16 +0000725 * @return The properties from the configuration object passed through the
726 * plugins or <code>null</code> if the configuration object has
727 * been newly created and no properties exist yet.
728 */
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000729 private Dictionary callPlugins( final String targetPid, final ServiceReference sr, final ConfigurationImpl cfg )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000730 {
Felix Meschbergera0903df2009-01-19 10:40:28 +0000731 // return a deep copy, since the plugins may tamper with the array
732 // and collection elements, which should not modify the internal data
733 Dictionary props = cfg.getProperties( true );
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000734
Felix Meschberger2941ef92007-08-20 13:15:16 +0000735 // guard against NPE for new configuration never updated
736 if (props == null) {
737 return null;
738 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000739
740 ServiceReference[] plugins = null;
741 try
742 {
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000743 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000744 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000745 }
746 catch ( InvalidSyntaxException ise )
747 {
748 // no filter, no exception ...
749 }
750
751 // abort early if there are no plugins
752 if ( plugins == null || plugins.length == 0 )
753 {
754 return props;
755 }
756
757 // sort the plugins by their service.cmRanking
758 SortedSet pluginSet = new TreeSet( cmRankComp );
Carsten Ziegeler7853b9a2008-01-11 16:30:24 +0000759 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000760 {
761 pluginSet.add( plugins[i] );
762 }
763
764 // call the plugins in order
765 for ( Iterator pi = pluginSet.iterator(); pi.hasNext(); )
766 {
767 ServiceReference pluginRef = ( ServiceReference ) pi.next();
768 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
769 try
770 {
771 plugin.modifyConfiguration( sr, props );
772 }
773 catch ( Throwable t )
774 {
775 log( LogService.LOG_ERROR, "Unexpected problem calling" + " configuration plugin", t );
776 }
777 finally
778 {
779 // ensure ungetting the plugin
780 bundleContext.ungetService( pluginRef );
781 }
782 cfg.setAutoProperties( props, false );
783 }
784
785 return props;
786 }
787
788
789 /**
790 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000791 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000792 * @param factoryPid
793 * @return
794 */
795 private static String createPid( String factoryPid )
796 {
797 SecureRandom ng = numberGenerator;
798 if ( ng == null )
799 {
800 numberGenerator = ng = new SecureRandom();
801 }
802
803 byte[] randomBytes = new byte[16];
804 ng.nextBytes( randomBytes );
805 randomBytes[6] &= 0x0f; /* clear version */
806 randomBytes[6] |= 0x40; /* set to version 4 */
807 randomBytes[8] &= 0x3f; /* clear variant */
808 randomBytes[8] |= 0x80; /* set to IETF variant */
809
810 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
811
812 // prefix the new pid with the factory pid
813 buf.append( factoryPid ).append( "." );
814
815 // serialize the UUID into the buffer
816 for ( int i = 0; i < randomBytes.length; i++ )
817 {
818
819 if ( i == 4 || i == 6 || i == 8 || i == 10 )
820 {
821 buf.append( '-' );
822 }
823
824 int val = randomBytes[i] & 0xff;
825 buf.append( Integer.toHexString( val >> 4 ) );
826 buf.append( Integer.toHexString( val & 0xf ) );
827 }
828
829 return buf.toString();
830 }
831
832
833 void log( int level, String message, Throwable t )
834 {
Felix Meschberger08282c32009-01-28 07:01:55 +0000835 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +0000836 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000837 if ( log != null )
838 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000839 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000840 return;
841 }
842
Felix Meschberger08282c32009-01-28 07:01:55 +0000843 // Otherwise only log if more serious than the configured level
844 if ( level <= logLevel )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000845 {
Felix Meschberger08282c32009-01-28 07:01:55 +0000846 String code;
847 switch ( level )
848 {
849 case LogService.LOG_INFO:
850 code = "*INFO *";
851 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000852
Felix Meschberger08282c32009-01-28 07:01:55 +0000853 case LogService.LOG_WARNING:
854 code = "*WARN *";
855 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000856
Felix Meschberger08282c32009-01-28 07:01:55 +0000857 case LogService.LOG_ERROR:
858 code = "*ERROR*";
859 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000860
Felix Meschberger08282c32009-01-28 07:01:55 +0000861 case LogService.LOG_DEBUG:
862 default:
863 code = "*DEBUG*";
864 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000865
Felix Meschberger08282c32009-01-28 07:01:55 +0000866 System.err.println( code + " " + message );
867 if ( t != null )
868 {
869 t.printStackTrace( System.err );
870 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000871 }
872 }
873
Felix Meschberger851c6412009-08-16 18:43:26 +0000874
875 /**
876 * Returns the <code>service.pid</code> property of the service reference as
877 * an array of strings or <code>null</code> if the service reference does
878 * not have a service PID property.
879 * <p>
880 * The service.pid property may be a single string, in which case a single
881 * element array is returned. If the property is an array of string, this
882 * array is returned. If the property is a collection it is assumed to be a
883 * collection of strings and the collection is converted to an array to be
884 * returned. Otherwise (also if the property is not set) <code>null</code>
885 * is returned.
886 *
887 * @throws NullPointerException
888 * if reference is <code>null</code>
889 * @throws ArrayStoreException
890 * if the service pid is a collection and not all elements are
891 * strings.
892 */
893 static String[] getServicePid( ServiceReference reference )
894 {
895 Object pidObj = reference.getProperty( Constants.SERVICE_PID );
896 if ( pidObj instanceof String )
897 {
898 return new String[]
899 { ( String ) pidObj };
900 }
901 else if ( pidObj instanceof String[] )
902 {
903 return ( String[] ) pidObj;
904 }
905 else if ( pidObj instanceof Collection )
906 {
907 Collection pidCollection = ( Collection ) pidObj;
908 return ( String[] ) pidCollection.toArray( new String[pidCollection.size()] );
909 }
910
911 return null;
912 }
913
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000914 // ---------- inner classes ------------------------------------------------
915
916 private class ManagedServiceUpdate implements Runnable
917 {
918 private String pid;
919
920 private ServiceReference sr;
921
922 private ManagedService service;
923
924
925 ManagedServiceUpdate( String pid, ServiceReference sr, ManagedService service )
926 {
927 this.pid = pid;
928 this.sr = sr;
929 this.service = service;
930 }
931
932
933 public void run()
934 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000935 // get or load configuration for the pid
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000936 ConfigurationImpl cfg;
937 try
938 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000939 cfg = getExistingConfiguration( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000940 }
941 catch ( IOException ioe )
942 {
943 log( LogService.LOG_ERROR, "Error loading configuration for " + pid, ioe );
944 return;
945 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000946
Felix Meschberger2941ef92007-08-20 13:15:16 +0000947 // this will be set below to be given to the service
948 Dictionary dictionary;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000949
Felix Meschberger56e2b7e2009-08-16 18:49:58 +0000950 // check configuration and call plugins if existing
951 if ( cfg != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000952 {
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000953
Felix Meschbergerf4631322008-03-10 12:32:35 +0000954 if ( cfg.isDelivered() )
955 {
956 log( LogService.LOG_DEBUG, "Configuration " + pid + " has already been delivered", null );
957 return;
958 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000959
Felix Meschberger41243192009-01-14 19:59:58 +0000960 Bundle serviceBundle = sr.getBundle();
961 if ( serviceBundle == null )
962 {
963 log( LogService.LOG_INFO, "ServiceFactory for PID " + pid
964 + " seems to already have been unregistered, not updating with configuration", null );
965 return;
966 }
967
Felix Meschberger2941ef92007-08-20 13:15:16 +0000968 // 104.3 Ignore duplicate PIDs from other bundles and report
969 // them to the log
970 // 104.4.1 No update call back for PID already bound to another
971 // bundle location
972 // 104.4.1 assign configuration to bundle if unassigned
Felix Meschberger41243192009-01-14 19:59:58 +0000973 String bundleLocation = serviceBundle.getLocation();
Felix Meschberger2941ef92007-08-20 13:15:16 +0000974 if ( cfg.getBundleLocation() == null )
975 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000976 // dynamically bind to the location of the service if unbound
977 cfg.setBundleLocation( bundleLocation, false );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000978 }
979 else if ( !bundleLocation.equals( cfg.getBundleLocation() ) )
980 {
981 log( LogService.LOG_ERROR, "Cannot use configuration for " + pid + " requested by bundle "
Felix Meschberger41243192009-01-14 19:59:58 +0000982 + serviceBundle.getLocation() + " but belongs to " + cfg.getBundleLocation(), null );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000983 return;
984 }
985
986 // 104.3 Report an error in the log if more than one service
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000987 // with the same PID asks for the configuration
Felix Meschberger2941ef92007-08-20 13:15:16 +0000988 if ( cfg.getServiceReference() != null && !sr.equals( cfg.getServiceReference() ) )
989 {
990 log( LogService.LOG_ERROR, "Configuration for " + pid + " has already been used for service "
991 + cfg.getServiceReference() + " and will now also be given to " + sr, null );
992 }
993 else
994 {
995 // assign the configuration to the service
996 cfg.setServiceReference( sr );
997 }
998
999 // prepare the configuration for the service (call plugins)
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001000 dictionary = callPlugins( pid, sr, cfg );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001001 }
1002 else
1003 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001004 // 104.5.3 ManagedService.updated must be called with null
1005 // if no configuration is available
1006 dictionary = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001007 }
1008
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001009 // update the service with the configuration
1010 try
1011 {
1012 service.updated( dictionary );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001013
1014 // if there is nothing to set, don't
1015 if ( cfg != null )
1016 {
1017 cfg.setDelivered( true );
1018 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001019 }
1020 catch ( ConfigurationException ce )
1021 {
1022 if ( ce.getProperty() != null )
1023 {
1024 log( LogService.LOG_ERROR, sr + ": Updating configuration property " + ce.getProperty()
1025 + " caused a problem: " + ce.getReason(), ce );
1026 }
1027 else
1028 {
1029 log( LogService.LOG_ERROR, sr + ": Updating configuration caused a problem: " + ce.getReason(), ce );
1030
1031 }
1032 }
1033 catch ( Throwable t )
1034 {
1035 log( LogService.LOG_ERROR, sr + ": Unexpected problem updating configuration", t );
1036 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001037 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001038
Felix Meschberger432e3872008-03-07 14:58:57 +00001039 public String toString()
1040 {
1041 return "ManagedService Update: pid=" + pid;
1042 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001043 }
1044
1045 private class ManagedServiceFactoryUpdate implements Runnable
1046 {
1047 private String factoryPid;
1048
1049 private ServiceReference sr;
1050
1051 private ManagedServiceFactory service;
1052
1053
1054 ManagedServiceFactoryUpdate( String factoryPid, ServiceReference sr, ManagedServiceFactory service )
1055 {
1056 this.factoryPid = factoryPid;
1057 this.sr = sr;
1058 this.service = service;
1059 }
1060
1061
1062 public void run()
1063 {
1064 Factory factory;
1065 try
1066 {
1067 factory = getFactory( factoryPid );
1068 }
1069 catch ( IOException ioe )
1070 {
1071 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID " + factoryPid, ioe );
1072 return;
1073 }
1074
Felix Meschberger41243192009-01-14 19:59:58 +00001075 Bundle serviceBundle = sr.getBundle();
1076 if ( serviceBundle == null )
1077 {
1078 log( LogService.LOG_INFO, "ManagedServiceFactory for factory PID " + factoryPid
1079 + " seems to already have been unregistered, not updating with factory", null );
1080 return;
1081 }
1082
1083 String bundleLocation = serviceBundle.getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001084 if ( factory.getBundleLocation() == null )
1085 {
1086 // bind to the location of the service if unbound
Felix Meschberger6a698df2009-08-16 18:38:46 +00001087 factory.setBundleLocation( bundleLocation, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001088 }
1089 else if ( !bundleLocation.equals( factory.getBundleLocation() ) )
1090 {
1091 // factory PID is bound to another bundle
1092 log( LogService.LOG_ERROR, "Cannot use Factory configuration for " + factoryPid
Felix Meschberger41243192009-01-14 19:59:58 +00001093 + " requested by bundle " + serviceBundle.getLocation() + " but belongs to "
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001094 + factory.getBundleLocation(), null );
1095 return;
1096 }
1097
1098 Set pids = factory.getPIDs();
1099
1100 for ( Iterator pi = pids.iterator(); pi.hasNext(); )
1101 {
1102 String pid = ( String ) pi.next();
1103 ConfigurationImpl cfg;
1104 try
1105 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001106 cfg = getExistingConfiguration( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001107 }
1108 catch ( IOException ioe )
1109 {
1110 log( LogService.LOG_ERROR, "Error loading configuration for " + pid, ioe );
1111 continue;
1112 }
1113
1114 // sanity check on the configuration
1115 if ( cfg == null )
1116 {
1117 log( LogService.LOG_ERROR, "Configuration " + pid + " referred to by factory " + factoryPid
1118 + " does not exist", null );
1119 factory.removePID( pid );
1120 factory.storeSilently();
1121 continue;
1122 }
Felix Meschberger2941ef92007-08-20 13:15:16 +00001123 else if ( cfg.isNew() )
1124 {
1125 // Configuration has just been created but not yet updated
1126 // we currently just ignore it and have the update mechanism
1127 // provide the configuration to the ManagedServiceFactory
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +00001128 // As of FELIX-612 (not storing new factory configurations)
1129 // this should not happen. We keep this for added stability
1130 // but raise the logging level to error.
1131 log( LogService.LOG_ERROR, "Ignoring new configuration pid=" + pid, null );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001132 continue;
1133 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001134 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1135 {
1136 log( LogService.LOG_ERROR, "Configuration " + pid + " referred to by factory " + factoryPid
Felix Meschbergerbb048982007-08-06 08:56:50 +00001137 + " seems to belong to factory " + cfg.getFactoryPid(), null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001138 factory.removePID( pid );
1139 factory.storeSilently();
1140 continue;
1141 }
1142
Felix Meschbergerf4631322008-03-10 12:32:35 +00001143 // do not re-updated unmodified configuration
1144 if ( cfg.isDelivered() )
1145 {
1146 log( LogService.LOG_DEBUG, "Configuration " + pid + " has already been updated", null );
1147 continue;
1148 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001149
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001150 // check bundle location of configuration
1151 if ( cfg.getBundleLocation() == null )
1152 {
Felix Meschberger6a698df2009-08-16 18:38:46 +00001153 // dynamically bind to the location of the service if unbound
1154 cfg.setBundleLocation( bundleLocation, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001155 }
1156 else if ( !bundleLocation.equals( cfg.getBundleLocation() ) )
1157 {
1158 // configuration is bound to another bundle
1159 log( LogService.LOG_ERROR, "Configuration " + pid + " (factory " + factoryPid
1160 + ") belongs to bundle " + cfg.getBundleLocation() + " but was requested for bundle "
1161 + bundleLocation, null );
1162 continue;
1163 }
1164
1165 // prepare the configuration for the service (call plugins)
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001166 // call the plugins with cm.target set to the service's factory PID
1167 // (clarification in Section 104.9.1 of Compendium 4.2)
1168 Dictionary dictionary = callPlugins( factoryPid, sr, cfg );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001169
1170 // update the service with the configuration
1171 try
1172 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001173 // only, if there is non-null configuration data
1174 if ( dictionary != null )
1175 {
Felix Meschberger432e3872008-03-07 14:58:57 +00001176 log( LogService.LOG_DEBUG, sr + ": Updating configuration pid=" + pid, null );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001177 service.updated( pid, dictionary );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001178 cfg.setDelivered( true );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001179 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001180 }
1181 catch ( ConfigurationException ce )
1182 {
1183 if ( ce.getProperty() != null )
1184 {
1185 log( LogService.LOG_ERROR, sr + ": Updating configuration property " + ce.getProperty()
1186 + " caused a problem: " + ce.getReason(), ce );
1187 }
1188 else
1189 {
1190 log( LogService.LOG_ERROR, sr + ": Updating configuration caused a problem: " + ce.getReason(),
1191 ce );
1192
1193 }
1194 }
1195 catch ( Throwable t )
1196 {
1197 log( LogService.LOG_ERROR, sr + ": Unexpected problem updating configuration", t );
1198 }
1199 }
1200 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001201
1202
Felix Meschberger432e3872008-03-07 14:58:57 +00001203 public String toString()
1204 {
1205 return "ManagedServiceFactory Update: factoryPid=" + factoryPid;
1206 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001207 }
1208
1209 private class UpdateConfiguration implements Runnable
1210 {
1211
1212 private ConfigurationImpl config;
1213
1214
1215 UpdateConfiguration( ConfigurationImpl config )
1216 {
1217 this.config = config;
1218 }
1219
1220
1221 public void run()
1222 {
Felix Meschbergerf4631322008-03-10 12:32:35 +00001223 if ( config.isDelivered() )
1224 {
1225 log( LogService.LOG_DEBUG, "Configuration " + config.getPid() + " has already been updated", null );
1226 return;
1227 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001228
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001229 try
1230 {
1231 if ( config.getFactoryPid() == null )
1232 {
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001233 final ServiceReference[] srList = bundleContext.getServiceReferences( ManagedService.class
1234 .getName(), "(" + Constants.SERVICE_PID + "=" + config.getPid() + ")" );
1235 if ( srList != null && srList.length > 0 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001236 {
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001237 final ServiceReference sr = srList[0];
1238 final ManagedService srv = ( ManagedService ) bundleContext.getService( sr );
1239
1240 // 104.3 Report an error in the log if more than one service
1241 // with the same PID asks for the configuration
1242 if ( srList.length > 1 )
1243 {
1244 for ( int i = 1; i < srList.length; i++ )
1245 {
1246 log( LogService.LOG_ERROR, "Configuration for " + config.getPid()
1247 + " is used for service " + sr
1248 + "following services will not receive configuration: " + srList[i], null );
1249 }
1250 }
1251
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001252 try
1253 {
1254 // bind the configuration, fail if bound to another
1255 // bundle !!
1256 // check bundle location of configuration
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001257 String bundleLocation = sr.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001258 if ( config.getBundleLocation() == null )
1259 {
Felix Meschberger6a698df2009-08-16 18:38:46 +00001260 // dynamically bind to the location of the service if unbound
1261 config.setBundleLocation( bundleLocation, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001262 }
1263 else if ( !bundleLocation.equals( config.getBundleLocation() ) )
1264 {
1265 // configuration is bound to another bundle
1266 log( LogService.LOG_ERROR, "Configuration " + config.getPid() + " belongs to bundle "
1267 + config.getBundleLocation() + " but was requested for bundle " + bundleLocation,
1268 null );
1269 return;
1270 }
1271
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001272 // record the delivery of the configuration
1273 if ( config.getServiceReference() == null )
1274 {
1275 config.setServiceReference( sr );
1276 }
1277
Felix Meschbergerbb048982007-08-06 08:56:50 +00001278 // prepare the configuration for the service (call plugins)
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001279 Dictionary dictionary = callPlugins( config.getPid(), sr, config );
Felix Meschbergerbb048982007-08-06 08:56:50 +00001280
1281 // update the ManagedService with the properties
1282 srv.updated( dictionary );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001283 config.setDelivered( true );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001284 }
1285 finally
1286 {
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001287 bundleContext.ungetService( sr );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001288 }
1289 }
1290 }
1291 else
1292 {
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001293 ServiceReference[] srList = bundleContext.getServiceReferences( ManagedServiceFactory.class
1294 .getName(), "(" + Constants.SERVICE_PID + "=" + config.getFactoryPid() + ")" );
1295 if ( srList != null && srList.length > 0 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001296 {
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001297 final ServiceReference sr = srList[0];
1298 final ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext.getService( sr );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001299 try
1300 {
1301 // bind the configuration, fail if bound to another
1302 // bundle !!
1303 // check bundle location of configuration
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001304 String bundleLocation = sr.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001305 if ( config.getBundleLocation() == null )
1306 {
Felix Meschberger6a698df2009-08-16 18:38:46 +00001307 // dynamically bind to the location of the service if unbound
1308 config.setBundleLocation( bundleLocation, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001309 }
1310 else if ( !bundleLocation.equals( config.getBundleLocation() ) )
1311 {
1312 // configuration is bound to another bundle
1313 log( LogService.LOG_ERROR, "Configuration " + config.getPid() + " (factory "
1314 + config.getFactoryPid() + ") belongs to bundle " + config.getBundleLocation()
1315 + " but was requested for bundle " + bundleLocation, null );
1316 return;
1317 }
1318
Felix Meschbergerbb048982007-08-06 08:56:50 +00001319 // prepare the configuration for the service (call plugins)
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001320 // call the plugins with cm.target set to the service's factory PID
1321 // (clarification in Section 104.9.1 of Compendium 4.2)
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001322 Dictionary dictionary = callPlugins( config.getFactoryPid(), sr, config );
Felix Meschbergerbb048982007-08-06 08:56:50 +00001323
1324 // update the ManagedServiceFactory with the properties
Felix Meschberger2941ef92007-08-20 13:15:16 +00001325 // only, if there is non-null configuration data
1326 if ( dictionary != null )
1327 {
1328 srv.updated( config.getPid(), dictionary );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001329 config.setDelivered( true );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001330 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001331 }
1332 finally
1333 {
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001334 bundleContext.ungetService( sr );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001335 }
1336 }
1337 }
1338 }
1339 catch ( ConfigurationException ce )
1340 {
1341 if ( ce.getProperty() != null )
1342 {
1343 log( LogService.LOG_ERROR, "Updating configuration property " + ce.getProperty()
1344 + " caused a problem: " + ce.getReason(), ce );
1345 }
1346 else
1347 {
1348 log( LogService.LOG_ERROR, "Updating configuration caused a problem: " + ce.getReason(), ce );
1349
1350 }
1351 }
1352 catch ( Throwable t )
1353 {
1354 log( LogService.LOG_ERROR, "Unexpected problem updating configuration", t );
1355 }
1356
Felix Meschberger66423332007-08-22 08:46:34 +00001357 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPid(), config.getFactoryPid() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001358 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001359
Felix Meschberger432e3872008-03-07 14:58:57 +00001360 public String toString()
1361 {
1362 return "Update: pid=" + config.getPid();
1363 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001364 }
1365
1366 private class DeleteConfiguration implements Runnable
1367 {
Felix Meschberger66423332007-08-22 08:46:34 +00001368
Felix Meschbergerf4631322008-03-10 12:32:35 +00001369 private ConfigurationImpl config;
Felix Meschberger66423332007-08-22 08:46:34 +00001370 private String pid;
1371 private String factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001372
1373
1374 DeleteConfiguration( ConfigurationImpl config )
1375 {
Felix Meschbergerf4631322008-03-10 12:32:35 +00001376 this.config = config;
Felix Meschberger66423332007-08-22 08:46:34 +00001377 this.pid = config.getPid();
1378 this.factoryPid = config.getFactoryPid();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001379 }
1380
1381
1382 public void run()
1383 {
Felix Meschbergerf4631322008-03-10 12:32:35 +00001384 if ( config.isDelivered() )
1385 {
1386 log( LogService.LOG_DEBUG, "Deletion of configuration " + pid + " has already been delivered", null );
1387 return;
1388 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001389
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001390 try
1391 {
Felix Meschberger66423332007-08-22 08:46:34 +00001392 if ( factoryPid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001393 {
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001394 ServiceReference[] srList = bundleContext.getServiceReferences( ManagedService.class.getName(), "("
Felix Meschberger66423332007-08-22 08:46:34 +00001395 + Constants.SERVICE_PID + "=" + pid + ")" );
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001396 if ( srList != null && srList.length > 0 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001397 {
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001398 final ServiceReference sr = srList[0];
1399 final ManagedService srv = ( ManagedService ) bundleContext.getService( sr );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001400 try
1401 {
1402 srv.updated( null );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001403 config.setDelivered( true );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001404 }
1405 finally
1406 {
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001407 bundleContext.ungetService( sr );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001408 }
1409 }
1410 }
1411 else
1412 {
1413 // remove the pid from the factory
Felix Meschberger66423332007-08-22 08:46:34 +00001414 Factory factory = getFactory( factoryPid );
1415 factory.removePID( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001416 factory.store();
1417
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001418 ServiceReference[] srList = bundleContext.getServiceReferences( ManagedServiceFactory.class
1419 .getName(), "(" + Constants.SERVICE_PID + "=" + factoryPid + ")" );
1420 if ( srList != null && srList.length > 0 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001421 {
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001422 final ServiceReference sr = srList[0];
1423 final ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext.getService( sr );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001424 try
1425 {
Felix Meschberger66423332007-08-22 08:46:34 +00001426 srv.deleted( pid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001427 config.setDelivered( true );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001428 }
1429 finally
1430 {
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001431 bundleContext.ungetService( sr );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001432 }
1433 }
1434 }
1435 }
1436 catch ( ConfigurationException ce )
1437 {
1438 if ( ce.getProperty() != null )
1439 {
1440 log( LogService.LOG_ERROR, "Updating configuration property " + ce.getProperty()
1441 + " caused a problem: " + ce.getReason(), ce );
1442 }
1443 else
1444 {
1445 log( LogService.LOG_ERROR, "Updating configuration caused a problem: " + ce.getReason(), ce );
1446
1447 }
1448 }
1449 catch ( Throwable t )
1450 {
1451 log( LogService.LOG_ERROR, "Unexpected problem updating configuration", t );
1452 }
1453
Felix Meschberger66423332007-08-22 08:46:34 +00001454 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, pid, factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001455 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001456
Felix Meschberger432e3872008-03-07 14:58:57 +00001457 public String toString()
1458 {
1459 return "Delete: pid=" + pid;
1460 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001461 }
1462
1463 private class FireConfigurationEvent implements Runnable
1464 {
1465 private int type;
1466
Felix Meschberger66423332007-08-22 08:46:34 +00001467 private String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001468
Felix Meschberger66423332007-08-22 08:46:34 +00001469 private String factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001470
1471
Felix Meschberger66423332007-08-22 08:46:34 +00001472 FireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001473 {
1474 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001475 this.pid = pid;
1476 this.factoryPid = factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001477 }
1478
1479
1480 public void run()
1481 {
1482 // get the listeners
1483 ServiceReference[] srs = configurationListenerTracker.getServiceReferences();
1484 if ( srs == null || srs.length == 0 )
1485 {
1486 return;
1487 }
1488
Felix Meschbergerb4f83e42009-01-15 08:53:36 +00001489 ConfigurationEvent event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001490
1491 for ( int i = 0; i < srs.length; i++ )
1492 {
1493 ConfigurationListener cl = ( ConfigurationListener ) configurationListenerTracker.getService( srs[i] );
1494 try
1495 {
1496 cl.configurationEvent( event );
1497 }
1498 catch ( Throwable t )
1499 {
1500 log( LogService.LOG_ERROR, "Unexpected problem delivery configuration event to " + srs[i], t );
1501 }
1502 }
1503 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001504
Felix Meschberger432e3872008-03-07 14:58:57 +00001505 public String toString()
1506 {
1507 return "Fire ConfigurationEvent: pid=" + pid;
1508 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001509 }
1510
Carsten Ziegeler41683982007-12-27 08:35:27 +00001511 private static abstract class AbstractManagedServiceTracker extends ServiceTracker
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001512 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001513 protected final ConfigurationManager cm;
1514
1515 AbstractManagedServiceTracker( ConfigurationManager cm, String className )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001516 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001517 super( cm.bundleContext, className, null );
1518 this.cm = cm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001519 open();
1520 }
1521
1522
1523 public void removedService( ServiceReference reference, Object service )
1524 {
1525 // check whether we can take back the configuration object
Felix Meschberger851c6412009-08-16 18:43:26 +00001526 String[] pids = getServicePid( reference );
1527 if ( pids != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001528 {
Felix Meschberger851c6412009-08-16 18:43:26 +00001529 for ( int i = 0; i < pids.length; i++ )
1530 {
1531 ConfigurationImpl cfg = cm.getCachedConfiguration( pids[i] );
Felix Meschberger6a698df2009-08-16 18:38:46 +00001532 if ( cfg != null && reference.equals( cfg.getServiceReference() ) )
1533 {
1534 cfg.setServiceReference( null );
1535 cfg.setDelivered( false );
1536 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001537 }
Felix Meschberger851c6412009-08-16 18:43:26 +00001538 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001539
1540 super.removedService( reference, service );
1541 }
1542 }
1543
Carsten Ziegeler41683982007-12-27 08:35:27 +00001544 private static class ManagedServiceTracker extends AbstractManagedServiceTracker
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001545 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001546
1547 ManagedServiceTracker(ConfigurationManager cm)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001548 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001549 super( cm, ManagedService.class.getName() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001550 }
1551
1552
1553 public Object addingService( ServiceReference reference )
1554 {
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001555 Object serviceObject = super.addingService( reference );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001556
1557 // configure the managed service
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001558 if ( serviceObject instanceof ManagedService )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001559 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001560 cm.configure(reference, ( ManagedService ) serviceObject);
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001561 }
1562 else
1563 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001564 cm.log( LogService.LOG_WARNING, "Service " + serviceObject + " is not a ManagedService", null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001565 }
1566
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001567 return serviceObject;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001568 }
1569 }
1570
Carsten Ziegeler41683982007-12-27 08:35:27 +00001571 private static class ManagedServiceFactoryTracker extends AbstractManagedServiceTracker
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001572 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001573 ManagedServiceFactoryTracker(ConfigurationManager cm)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001574 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001575 super( cm, ManagedServiceFactory.class.getName() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001576 }
1577
1578
1579 public Object addingService( ServiceReference reference )
1580 {
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001581 Object serviceObject = super.addingService( reference );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001582
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001583 // configure the managed service factory
1584 if ( serviceObject instanceof ManagedServiceFactory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001585 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001586 cm.configure( reference, ( ManagedServiceFactory ) serviceObject );
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001587 }
1588 else
1589 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001590 cm.log( LogService.LOG_WARNING, "Service " + serviceObject + " is not a ManagedServiceFactory", null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001591 }
1592
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001593 return serviceObject;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001594 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001595
Felix Meschberger6a698df2009-08-16 18:38:46 +00001596
Felix Meschbergerf4631322008-03-10 12:32:35 +00001597 public void removedService( ServiceReference reference, Object service )
1598 {
1599 // check whether we can take back the configuration objects
Felix Meschberger851c6412009-08-16 18:43:26 +00001600 String[] factoryPids = getServicePid( reference );
1601 if ( factoryPids != null )
Felix Meschbergerf4631322008-03-10 12:32:35 +00001602 {
Felix Meschberger851c6412009-08-16 18:43:26 +00001603 for ( int i = 0; i < factoryPids.length; i++ )
1604 {
1605 Factory factory = cm.getCachedFactory( factoryPids[i] );
Felix Meschberger6a698df2009-08-16 18:38:46 +00001606 if ( factory != null )
Felix Meschbergerf4631322008-03-10 12:32:35 +00001607 {
Felix Meschberger6a698df2009-08-16 18:38:46 +00001608 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
Felix Meschbergerf4631322008-03-10 12:32:35 +00001609 {
Felix Meschberger6a698df2009-08-16 18:38:46 +00001610 String pid = ( String ) pi.next();
1611 ConfigurationImpl cfg = cm.getCachedConfiguration( pid );
1612 if ( cfg != null )
1613 {
1614 cfg.setDelivered( false );
1615 }
Felix Meschbergerf4631322008-03-10 12:32:35 +00001616 }
1617 }
1618 }
Felix Meschberger851c6412009-08-16 18:43:26 +00001619 }
Felix Meschbergerf4631322008-03-10 12:32:35 +00001620
1621 super.removedService( reference, service );
1622 }
1623
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001624 }
1625}