blob: 82590edb6a245d77df545eac518268a1d7f6a3f2 [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 Meschberger3f9e4da2009-08-17 07:52:39 +0000144 /**
145 * The map of dynamic configuration bindings. This maps the
146 * PID of the dynamically bound configuration or factory to its bundle
147 * location.
148 * <p>
149 * On bundle startup this map is loaded from persistence and validated
150 * against the locations of installed bundles: Entries pointing to bundle
151 * locations not currently installed are removed.
152 * <p>
153 * The map is written to persistence on each change.
154 */
155 private DynamicBindings dynamicBindings;
156
Felix Meschberger08282c32009-01-28 07:01:55 +0000157 // the maximum log level when no LogService is available
158 private int logLevel = CM_LOG_LEVEL_DEFAULT;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000159
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000160 // flag indicating whether BundleChange events should be consumed (FELIX-979)
161 private volatile boolean handleBundleEvents;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000162
163 public void start( BundleContext bundleContext )
164 {
165 // track the log service using a ServiceTracker
Felix Meschberger85b355d2007-08-31 07:17:38 +0000166 logTracker = new ServiceTracker( bundleContext, LOG_SERVICE_NAME , null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000167 logTracker.open();
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000168
Felix Meschberger08282c32009-01-28 07:01:55 +0000169 // assign the log level
170 String logLevelProp = bundleContext.getProperty( CM_LOG_LEVEL );
171 if ( logLevelProp == null )
172 {
173 logLevel = CM_LOG_LEVEL_DEFAULT;
174 }
175 else
176 {
177 try
178 {
179 logLevel = Integer.parseInt( logLevelProp );
180 }
181 catch ( NumberFormatException nfe )
182 {
183 logLevel = CM_LOG_LEVEL_DEFAULT;
184 }
185 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000186
187 // set up some fields
188 this.bundleContext = bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000189
190 // configurationlistener support
191 configurationListenerTracker = new ServiceTracker( bundleContext, ConfigurationListener.class.getName(), null );
192 configurationListenerTracker.open();
193
194 // initialize the asynchonous updater thread
195 this.updateThread = new UpdateThread( this );
196 this.updateThread.start();
197
198 // set up the location (might throw IllegalArgumentException)
199 try
200 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000201 FilePersistenceManager fpm = new FilePersistenceManager( bundleContext, bundleContext
202 .getProperty( CM_CONFIG_DIR ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000203 Hashtable props = new Hashtable();
204 props.put( Constants.SERVICE_PID, fpm.getClass().getName() );
205 props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
206 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
207 props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
208 bundleContext.registerService( PersistenceManager.class.getName(), fpm, props );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000209
210 // setup dynamic configuration bindings
211 dynamicBindings = new DynamicBindings( bundleContext, fpm );
212 }
213 catch ( IOException ioe )
214 {
215 log( LogService.LOG_ERROR, "Failure setting up dynamic configuration bindings", ioe );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000216 }
217 catch ( IllegalArgumentException iae )
218 {
219 log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
220 }
221
222 // register as bundle and service listener
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000223 handleBundleEvents = true;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000224 bundleContext.addBundleListener( this );
225
226 // get all persistence managers to begin with
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000227 pmtCount = 1; // make sure to get the persistence managers at least once
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000228 persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
229 persistenceManagerTracker.open();
230
231 // create and register configuration admin - start after PM tracker ...
232 ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
233 Hashtable props = new Hashtable();
234 props.put( Constants.SERVICE_PID, "org.apache.felix.cm.ConfigurationAdmin" );
235 props.put( Constants.SERVICE_DESCRIPTION, "Configuration Admin Service Specification 1.2 Implementation" );
236 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000237 configurationAdminRegistration = bundleContext.registerService( ConfigurationAdmin.class.getName(), caf, props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000238
239 // start handling ManagedService[Factory] services
Carsten Ziegeler41683982007-12-27 08:35:27 +0000240 managedServiceTracker = new ManagedServiceTracker(this);
241 managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this);
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000242 }
243
244
245 public void stop( BundleContext bundleContext )
246 {
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000247
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000248 // stop handling bundle events immediately
249 handleBundleEvents = false;
250
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000251 // immediately unregister the Configuration Admin before cleaning up
Felix Meschberger10568352009-01-15 08:57:11 +0000252 // clearing the field before actually unregistering the service
253 // prevents IllegalStateException in getServiceReference() if
254 // the field is not null but the service already unregistered
255 if (configurationAdminRegistration != null) {
256 ServiceRegistration reg = configurationAdminRegistration;
257 configurationAdminRegistration = null;
258 reg.unregister();
259 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000260
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000261 // stop handling ManagedService[Factory] services
262 managedServiceFactoryTracker.close();
263 managedServiceTracker.close();
264
265 // don't care for PersistenceManagers any more
266 persistenceManagerTracker.close();
267
268 // stop listening for events
269 bundleContext.removeBundleListener( this );
270
271 if ( configurationListenerTracker != null )
272 {
273 configurationListenerTracker.close();
274 }
275
276 if ( updateThread != null )
277 {
278 // terminate asynchrounous updates
279 updateThread.terminate();
280
281 // wait for all updates to terminate
282 try
283 {
284 updateThread.join();
285 }
286 catch ( InterruptedException ie )
287 {
288 // don't really care
289 }
290 }
291
292 if ( logTracker != null )
293 {
294 logTracker.close();
295 }
296
Felix Meschberger6a698df2009-08-16 18:38:46 +0000297 // just ensure the configuration cache is empty
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000298 synchronized ( configurations )
299 {
300 configurations.clear();
301 }
302
Felix Meschberger6a698df2009-08-16 18:38:46 +0000303 // just ensure the factory cache is empty
304 synchronized ( factories )
305 {
306 factories.clear();
307 }
308
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000309 this.bundleContext = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000310 }
311
312
313 // ---------- Configuration caching support --------------------------------
314
315 ConfigurationImpl getCachedConfiguration( String pid )
316 {
317 synchronized ( configurations )
318 {
319 return ( ConfigurationImpl ) configurations.get( pid );
320 }
321 }
322
323
Felix Meschberger6a698df2009-08-16 18:38:46 +0000324 ConfigurationImpl[] getCachedConfigurations()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000325 {
326 synchronized ( configurations )
327 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000328 return ( ConfigurationImpl[] ) configurations.values().toArray(
329 new ConfigurationImpl[configurations.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000330 }
331 }
332
333
Felix Meschberger2941ef92007-08-20 13:15:16 +0000334 ConfigurationImpl cacheConfiguration( ConfigurationImpl configuration )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000335 {
336 synchronized ( configurations )
337 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000338 Object existing = configurations.get( configuration.getPid() );
339 if ( existing != null )
340 {
341 return ( ConfigurationImpl ) existing;
342 }
343
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000344 configurations.put( configuration.getPid(), configuration );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000345 return configuration;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000346 }
347 }
348
349
350 void removeConfiguration( ConfigurationImpl configuration )
351 {
352 synchronized ( configurations )
353 {
354 configurations.remove( configuration.getPid() );
355 }
356 }
357
358
Felix Meschberger6a698df2009-08-16 18:38:46 +0000359 Factory getCachedFactory( String factoryPid )
360 {
361 synchronized ( factories )
362 {
363 return ( Factory ) factories.get( factoryPid );
364 }
365 }
366
367
368 Factory[] getCachedFactories()
369 {
370 synchronized ( factories )
371 {
372 return ( Factory[] ) factories.values().toArray( new Factory[factories.size()] );
373 }
374 }
375
376
377 void cacheFactory( Factory factory )
378 {
379 synchronized ( factories )
380 {
381 factories.put( factory.getFactoryPid(), factory );
382 }
383 }
384
385
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000386 // ---------- ConfigurationAdminImpl support
Felix Meschberger6a698df2009-08-16 18:38:46 +0000387
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000388 void setDynamicBundleLocation( final String pid, final String location )
389 {
390 if ( dynamicBindings != null )
391 {
392 try
393 {
394 dynamicBindings.putLocation( pid, location );
395 }
396 catch ( IOException ioe )
397 {
398 log( LogService.LOG_ERROR, "Failed storing dynamic configuration binding for " + pid + " to "
399 + location, ioe );
400 }
401 }
402 }
403
404
405 String getDynamicBundleLocation( final String pid )
406 {
407 if ( dynamicBindings != null )
408 {
409 return dynamicBindings.getLocation( pid );
410 }
411
412 return null;
413 }
414
415
416 // ---------- ConfigurationAdminImpl support
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000417
418 /*
419 * (non-Javadoc)
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000420 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000421 * @see org.osgi.service.cm.ConfigurationAdmin#createFactoryConfiguration(java.lang.String)
422 */
423 ConfigurationImpl createFactoryConfiguration( ConfigurationAdminImpl configurationAdmin, String factoryPid )
424 throws IOException
425 {
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000426 // check Persmission if factory is bound to another bundle
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000427 Factory factory = getFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000428 if ( factory.getBundleLocation() != null
429 && !factory.getBundleLocation().equals( configurationAdmin.getBundle().getLocation() ) )
430 {
431 configurationAdmin.checkPermission();
432 }
433
434 // create the configuration
435 String pid = createPid( factoryPid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000436 ConfigurationImpl config = createConfiguration( pid, factoryPid, configurationAdmin.getBundle().getLocation() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000437
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000438 return config;
439 }
440
441
442 /*
443 * (non-Javadoc)
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000444 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000445 * @see org.osgi.service.cm.ConfigurationAdmin#createFactoryConfiguration(java.lang.String,
446 * java.lang.String)
447 */
448 ConfigurationImpl createFactoryConfiguration( String factoryPid, String location ) throws IOException
449 {
450 // create the configuration
451 String pid = createPid( factoryPid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000452 ConfigurationImpl config = createConfiguration( pid, factoryPid, location );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000453
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000454 return config;
455 }
456
457
Felix Meschberger2941ef92007-08-20 13:15:16 +0000458 ConfigurationImpl getExistingConfiguration( String pid ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000459 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000460 ConfigurationImpl config = getCachedConfiguration( pid );
461 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000462 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000463 return config;
464 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000465
Felix Meschberger2941ef92007-08-20 13:15:16 +0000466 PersistenceManager[] pmList = getPersistenceManagers();
467 for ( int i = 0; i < pmList.length; i++ )
468 {
469 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000470 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000471 Dictionary props = pmList[i].load( pid );
472 config = new ConfigurationImpl( this, pmList[i], props );
473 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000474 }
475 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000476
Felix Meschberger2941ef92007-08-20 13:15:16 +0000477 // neither the cache nor any persistence manager has configuration
478 return null;
479 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000480
481
Felix Meschberger2941ef92007-08-20 13:15:16 +0000482 ConfigurationImpl getConfiguration( String pid, String bundleLocation ) throws IOException
483 {
484 // check for existing (cached or persistent) configuration
485 ConfigurationImpl config = getExistingConfiguration( pid );
486 if ( config != null )
487 {
488 return config;
489 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000490
Felix Meschberger2941ef92007-08-20 13:15:16 +0000491 // else create new configuration also setting the bundle location
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000492 // and cache the new configuration
493 config = createConfiguration( pid, null, bundleLocation );
494 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000495 }
496
497
498 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
499 throws IOException, InvalidSyntaxException
500 {
501 Filter filter = null;
502 if ( filterString != null )
503 {
504 filter = bundleContext.createFilter( filterString );
505 }
506
507 boolean unprivileged = configurationAdmin != null && !configurationAdmin.hasPermission();
508 String location = unprivileged ? configurationAdmin.getBundle().getLocation() : null;
509
510 List configList = new ArrayList();
511
512 PersistenceManager[] pmList = getPersistenceManagers();
513 for ( int i = 0; i < pmList.length; i++ )
514 {
515 Enumeration configs = pmList[i].getDictionaries();
516 while ( configs.hasMoreElements() )
517 {
518 Dictionary config = ( Dictionary ) configs.nextElement();
519
520 // ignore non-Configuration dictionaries
Felix Meschberger86a0d172007-07-04 07:15:01 +0000521 String pid = ( String ) config.get( Constants.SERVICE_PID );
522 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000523 {
524 continue;
525 }
526
527 // ignore this config if not privileged and not bound to bundle
528 if ( unprivileged )
529 {
530 Object boundLocation = config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION );
531 if ( !location.equals( boundLocation ) )
532 {
533 continue;
534 }
535 }
536
537 // check filter
538 if ( filter == null || filter.match( config ) )
539 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000540 // ensure the service.pid and returned a cached config if available
541 ConfigurationImpl cfg = getCachedConfiguration( pid );
542 if ( cfg == null )
543 {
544 cfg = new ConfigurationImpl( this, pmList[i], config );
545 }
546
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000547 // FELIX-611: Ignore configuration objects without props
548 if ( !cfg.isNew() )
549 {
550 configList.add( cfg );
551 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000552 }
553 }
554 }
555
Felix Meschberger8faceff2007-07-04 07:19:48 +0000556 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000557 .size()] );
558 }
559
560
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000561 void deleted( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000562 {
563 // remove the configuration from the cache
564 removeConfiguration( config );
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000565 updateThread.schedule( new DeleteConfiguration( config, true ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000566 }
567
568
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000569 void updated( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000570 {
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000571 updateThread.schedule( new UpdateConfiguration( config, true ) );
572 }
573
574
575 void revokeConfiguration( ConfigurationImpl config )
576 {
577 updateThread.schedule( new DeleteConfiguration( config, false ) );
578
579 // immediately unbind the configuration
580 config.setDynamicBundleLocation( null );
581 config.setServiceReference( null );
582 }
583
584
585 void reassignConfiguration( ConfigurationImpl config )
586 {
587 updateThread.schedule( new UpdateConfiguration( config, false ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000588 }
589
590
Felix Meschberger66423332007-08-22 08:46:34 +0000591 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000592 {
593
Felix Meschberger66423332007-08-22 08:46:34 +0000594 updateThread.schedule( new FireConfigurationEvent( type, pid, factoryPid) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000595 }
596
597
598 // ---------- BundleListener -----------------------------------------------
599
600 public void bundleChanged( BundleEvent event )
601 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000602 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000603 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000604 final String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000605
Felix Meschberger6a698df2009-08-16 18:38:46 +0000606 // we only reset dynamic bindings, which are only present in
607 // cached configurations, hence only consider cached configs here
608 final ConfigurationImpl[] configs = getCachedConfigurations();
609 for ( int i = 0; i < configs.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000610 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000611 final ConfigurationImpl cfg = configs[i];
Felix Meschberger41cce522009-08-19 05:54:40 +0000612 if ( location.equals( cfg.getDynamicBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000613 {
Felix Meschberger41cce522009-08-19 05:54:40 +0000614 cfg.setDynamicBundleLocation( null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000615 }
616 }
Felix Meschberger6a698df2009-08-16 18:38:46 +0000617
618 // we only reset dynamic bindings, which are only present in
619 // cached factories, hence only consider cached factories here
620 final Factory[] factories = getCachedFactories();
621 for ( int i = 0; i < factories.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000622 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000623 final Factory factory = factories[i];
Felix Meschberger41cce522009-08-19 05:54:40 +0000624 if ( location.equals( factory.getDynamicBundleLocation() ) )
Felix Meschberger6a698df2009-08-16 18:38:46 +0000625 {
Felix Meschberger41cce522009-08-19 05:54:40 +0000626 factory.setDynamicBundleLocation( null );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000627 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000628 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000629 }
630 }
631
632
633 // ---------- internal -----------------------------------------------------
634
635 private PersistenceManager[] getPersistenceManagers()
636 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000637 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
638 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000639 {
640
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000641 List pmList = new ArrayList();
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000642 PersistenceManager[] pm;
643
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000644 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
645 if ( refs == null || refs.length == 0 )
646 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000647 pm = new PersistenceManager[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000648 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000649 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000650 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000651 // sort the references according to the cmRanking property
652 SortedSet pms = new TreeSet( new RankingComparator( false ) );
653 for ( int i = 0; i < refs.length; i++ )
654 {
655 pms.add( refs[i] );
656 }
657
658 // create the service array from the sorted set of referenecs
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000659 int pmIndex = 0;
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000660 for ( Iterator pi = pms.iterator(); pi.hasNext(); pmIndex++ )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000661 {
662 ServiceReference ref = ( ServiceReference ) pi.next();
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000663 Object service = persistenceManagerTracker.getService( ref );
664 if ( service != null )
665 {
666 pmList.add( service );
667 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000668 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000669
670 pm = ( PersistenceManager[] ) pmList.toArray( new PersistenceManager[pmList.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000671 }
672
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000673 pmtCount = pm.length;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000674 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000675 }
676
677 return persistenceManagers;
678 }
679
680
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000681 private ServiceReference getServiceReference()
682 {
683 ServiceRegistration reg = configurationAdminRegistration;
684 return ( reg != null ) ? reg.getReference() : null;
685 }
686
687
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000688 private void configure( ServiceReference sr, ManagedService service )
689 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000690 String[] pids = getServicePid( sr );
691 if ( pids != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000692 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000693 for ( int i = 0; i < pids.length; i++ )
694 {
695 ManagedServiceUpdate update = new ManagedServiceUpdate( pids[i], sr, service );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000696 updateThread.schedule( update );
697 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000698 }
Felix Meschberger851c6412009-08-16 18:43:26 +0000699 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000700
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000701
702 private void configure( ServiceReference sr, ManagedServiceFactory service )
703 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000704 String[] pids = getServicePid( sr );
705 if ( pids != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000706 {
Felix Meschberger851c6412009-08-16 18:43:26 +0000707 for ( int i = 0; i < pids.length; i++ )
708 {
709 ManagedServiceFactoryUpdate update = new ManagedServiceFactoryUpdate( pids[i], sr, service );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000710 updateThread.schedule( update );
711 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000712 }
Felix Meschberger851c6412009-08-16 18:43:26 +0000713 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000714
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000715
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000716 /**
717 * Factory method to create a new configuration object. The configuration
718 * object returned is not stored in configuration cache and only persisted
719 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000720 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000721 * @param pid
722 * The PID of the new configuration object. Must not be
723 * <code>null</code>.
724 * @param factoryPid
725 * The factory PID of the new configuration. Not
Felix Meschberger6a698df2009-08-16 18:38:46 +0000726 * <code>null</code> if the new configuration object belongs to a
727 * factory. The configuration object will not be persisted if
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000728 * this parameter is not <code>null</code>.
729 * @param bundleLocation
730 * The bundle location of the bundle to which the configuration
Felix Meschberger6a698df2009-08-16 18:38:46 +0000731 * belongs or <code>null</code> if the configuration is not bound
732 * yet.
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000733 * @return The new configuration object
734 * @throws IOException
735 * May be thrown if an error occurrs persisting the new
736 * configuration object.
737 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000738 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000739 {
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000740 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000741 }
742
743
744 Factory getFactory( String factoryPid ) throws IOException
745 {
Felix Meschbergerf4631322008-03-10 12:32:35 +0000746 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000747 if ( factory != null )
748 {
749 return factory;
750 }
751
752 PersistenceManager[] pmList = getPersistenceManagers();
753 for ( int i = 0; i < pmList.length; i++ )
754 {
755 if ( Factory.exists( pmList[i], factoryPid ) )
756 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000757 factory = Factory.load( this, pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000758 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000759 return factory;
760 }
761 }
762
763 // if getting here, there is no configuration yet, optionally create new
764 return createFactory( factoryPid );
765 }
766
767
768 Factory createFactory( String factoryPid )
769 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000770 Factory factory = new Factory( this, getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000771 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000772 return factory;
773 }
774
775
Felix Meschberger2941ef92007-08-20 13:15:16 +0000776 /**
777 * Calls the registered configuration plugins on the given configuration
Felix Meschberger41cce522009-08-19 05:54:40 +0000778 * properties from the given configuration object unless the configuration
779 * has just been created and not been updated yet.
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000780 *
Felix Meschberger41cce522009-08-19 05:54:40 +0000781 * @param props The configuraiton properties run through the registered
782 * ConfigurationPlugin services. This may be <code>null</code>
783 * in which case this method just immediately returns.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000784 * @param targetPid The identification of the configuration update used to
785 * select the plugins according to their cm.target service
786 * property
Felix Meschberger2941ef92007-08-20 13:15:16 +0000787 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000788 * is to be updated with configuration
Felix Meschberger2941ef92007-08-20 13:15:16 +0000789 * @param cfg The configuration object whose properties have to be passed
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000790 * through the plugins
Felix Meschberger2941ef92007-08-20 13:15:16 +0000791 */
Felix Meschberger41cce522009-08-19 05:54:40 +0000792 private void callPlugins( final Dictionary props, final String targetPid, final ServiceReference sr,
793 final ConfigurationImpl cfg )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000794 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000795 // guard against NPE for new configuration never updated
796 if (props == null) {
Felix Meschberger41cce522009-08-19 05:54:40 +0000797 return;
Felix Meschberger2941ef92007-08-20 13:15:16 +0000798 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000799
800 ServiceReference[] plugins = null;
801 try
802 {
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000803 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000804 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000805 }
806 catch ( InvalidSyntaxException ise )
807 {
808 // no filter, no exception ...
809 }
810
811 // abort early if there are no plugins
812 if ( plugins == null || plugins.length == 0 )
813 {
Felix Meschberger41cce522009-08-19 05:54:40 +0000814 return;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000815 }
816
817 // sort the plugins by their service.cmRanking
818 SortedSet pluginSet = new TreeSet( cmRankComp );
Carsten Ziegeler7853b9a2008-01-11 16:30:24 +0000819 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000820 {
821 pluginSet.add( plugins[i] );
822 }
823
824 // call the plugins in order
825 for ( Iterator pi = pluginSet.iterator(); pi.hasNext(); )
826 {
827 ServiceReference pluginRef = ( ServiceReference ) pi.next();
828 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
829 try
830 {
831 plugin.modifyConfiguration( sr, props );
832 }
833 catch ( Throwable t )
834 {
Felix Meschberger41cce522009-08-19 05:54:40 +0000835 log( LogService.LOG_ERROR, "Unexpected problem calling configuration plugin " + toString( pluginRef ),
836 t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000837 }
838 finally
839 {
840 // ensure ungetting the plugin
841 bundleContext.ungetService( pluginRef );
842 }
843 cfg.setAutoProperties( props, false );
844 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000845 }
846
847
848 /**
849 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000850 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000851 * @param factoryPid
852 * @return
853 */
854 private static String createPid( String factoryPid )
855 {
856 SecureRandom ng = numberGenerator;
857 if ( ng == null )
858 {
859 numberGenerator = ng = new SecureRandom();
860 }
861
862 byte[] randomBytes = new byte[16];
863 ng.nextBytes( randomBytes );
864 randomBytes[6] &= 0x0f; /* clear version */
865 randomBytes[6] |= 0x40; /* set to version 4 */
866 randomBytes[8] &= 0x3f; /* clear variant */
867 randomBytes[8] |= 0x80; /* set to IETF variant */
868
869 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
870
871 // prefix the new pid with the factory pid
872 buf.append( factoryPid ).append( "." );
873
874 // serialize the UUID into the buffer
875 for ( int i = 0; i < randomBytes.length; i++ )
876 {
877
878 if ( i == 4 || i == 6 || i == 8 || i == 10 )
879 {
880 buf.append( '-' );
881 }
882
883 int val = randomBytes[i] & 0xff;
884 buf.append( Integer.toHexString( val >> 4 ) );
885 buf.append( Integer.toHexString( val & 0xf ) );
886 }
887
888 return buf.toString();
889 }
890
891
892 void log( int level, String message, Throwable t )
893 {
Felix Meschberger08282c32009-01-28 07:01:55 +0000894 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +0000895 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000896 if ( log != null )
897 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000898 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000899 return;
900 }
901
Felix Meschberger08282c32009-01-28 07:01:55 +0000902 // Otherwise only log if more serious than the configured level
903 if ( level <= logLevel )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000904 {
Felix Meschberger08282c32009-01-28 07:01:55 +0000905 String code;
906 switch ( level )
907 {
908 case LogService.LOG_INFO:
909 code = "*INFO *";
910 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000911
Felix Meschberger08282c32009-01-28 07:01:55 +0000912 case LogService.LOG_WARNING:
913 code = "*WARN *";
914 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000915
Felix Meschberger08282c32009-01-28 07:01:55 +0000916 case LogService.LOG_ERROR:
917 code = "*ERROR*";
918 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000919
Felix Meschberger08282c32009-01-28 07:01:55 +0000920 case LogService.LOG_DEBUG:
921 default:
922 code = "*DEBUG*";
923 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000924
Felix Meschberger08282c32009-01-28 07:01:55 +0000925 System.err.println( code + " " + message );
926 if ( t != null )
927 {
928 t.printStackTrace( System.err );
929 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000930 }
931 }
932
Felix Meschberger851c6412009-08-16 18:43:26 +0000933
934 /**
935 * Returns the <code>service.pid</code> property of the service reference as
936 * an array of strings or <code>null</code> if the service reference does
937 * not have a service PID property.
938 * <p>
939 * The service.pid property may be a single string, in which case a single
940 * element array is returned. If the property is an array of string, this
941 * array is returned. If the property is a collection it is assumed to be a
942 * collection of strings and the collection is converted to an array to be
943 * returned. Otherwise (also if the property is not set) <code>null</code>
944 * is returned.
945 *
946 * @throws NullPointerException
947 * if reference is <code>null</code>
948 * @throws ArrayStoreException
949 * if the service pid is a collection and not all elements are
950 * strings.
951 */
952 static String[] getServicePid( ServiceReference reference )
953 {
954 Object pidObj = reference.getProperty( Constants.SERVICE_PID );
955 if ( pidObj instanceof String )
956 {
957 return new String[]
958 { ( String ) pidObj };
959 }
960 else if ( pidObj instanceof String[] )
961 {
962 return ( String[] ) pidObj;
963 }
964 else if ( pidObj instanceof Collection )
965 {
966 Collection pidCollection = ( Collection ) pidObj;
967 return ( String[] ) pidCollection.toArray( new String[pidCollection.size()] );
968 }
969
970 return null;
971 }
972
Felix Meschberger41cce522009-08-19 05:54:40 +0000973
974 static String toString( ServiceReference ref )
975 {
976 String[] ocs = ( String[] ) ref.getProperty( "objectClass" );
977 String oc = "[";
978 for ( int i = 0; i < ocs.length; i++ )
979 {
980 oc += ocs[i];
981 if ( i < ocs.length - 1 )
982 oc += ", ";
983 }
984
985 oc += ", id=" + ref.getProperty( Constants.SERVICE_ID );
986 oc += ", bundle=" + ref.getBundle().getBundleId();
987 oc += "]";
988 return oc;
989 }
990
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000991 // ---------- inner classes ------------------------------------------------
992
993 private class ManagedServiceUpdate implements Runnable
994 {
Felix Meschberger41cce522009-08-19 05:54:40 +0000995 private final String pid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000996
Felix Meschberger41cce522009-08-19 05:54:40 +0000997 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000998
Felix Meschberger41cce522009-08-19 05:54:40 +0000999 private final ManagedService service;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001000
Felix Meschberger41cce522009-08-19 05:54:40 +00001001 private final ConfigurationImpl config;
1002
1003 private final Dictionary rawProperties;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001004
1005 ManagedServiceUpdate( String pid, ServiceReference sr, ManagedService service )
1006 {
1007 this.pid = pid;
1008 this.sr = sr;
1009 this.service = service;
Felix Meschberger41cce522009-08-19 05:54:40 +00001010
1011 // get or load configuration for the pid
1012 ConfigurationImpl config = null;
1013 Dictionary rawProperties = null;
1014 try
1015 {
1016 config = getExistingConfiguration( pid );
1017 if (config != null) {
1018 rawProperties = config.getProperties( true );
1019 }
1020 }
1021 catch ( IOException ioe )
1022 {
1023 log( LogService.LOG_ERROR, "Error loading configuration for " + pid, ioe );
1024 }
1025
1026 this.config = config;
1027 this.rawProperties = rawProperties;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001028 }
1029
1030
1031 public void run()
1032 {
Felix Meschberger56e2b7e2009-08-16 18:49:58 +00001033 // check configuration and call plugins if existing
Felix Meschberger41cce522009-08-19 05:54:40 +00001034 Dictionary properties = rawProperties;
1035 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001036 {
Felix Meschberger41243192009-01-14 19:59:58 +00001037 Bundle serviceBundle = sr.getBundle();
1038 if ( serviceBundle == null )
1039 {
1040 log( LogService.LOG_INFO, "ServiceFactory for PID " + pid
1041 + " seems to already have been unregistered, not updating with configuration", null );
1042 return;
1043 }
1044
Felix Meschberger2941ef92007-08-20 13:15:16 +00001045 // 104.3 Ignore duplicate PIDs from other bundles and report
1046 // them to the log
1047 // 104.4.1 No update call back for PID already bound to another
1048 // bundle location
1049 // 104.4.1 assign configuration to bundle if unassigned
Felix Meschberger41cce522009-08-19 05:54:40 +00001050 if ( !config.tryBindLocation( serviceBundle.getLocation() ) )
Felix Meschberger2941ef92007-08-20 13:15:16 +00001051 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001052 log( LogService.LOG_ERROR, "Cannot use configuration " + pid + " for "
1053 + ConfigurationManager.toString( sr ) + ": Configuration bound to bundle "
1054 + config.getBundleLocation(), null );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001055 return;
1056 }
1057
1058 // 104.3 Report an error in the log if more than one service
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001059 // with the same PID asks for the configuration
Felix Meschberger41cce522009-08-19 05:54:40 +00001060 if ( config.getServiceReference() == null )
Felix Meschberger2941ef92007-08-20 13:15:16 +00001061 {
1062 // assign the configuration to the service
Felix Meschberger41cce522009-08-19 05:54:40 +00001063 config.setServiceReference( sr );
1064 }
1065 else if ( !sr.equals( config.getServiceReference() ) )
1066 {
1067 log( LogService.LOG_ERROR, "Configuration for " + pid + " has already been used for service "
1068 + ConfigurationManager.toString( config.getServiceReference() )
1069 + " and will now also be given to " + ConfigurationManager.toString( sr ), null );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001070 }
1071
1072 // prepare the configuration for the service (call plugins)
Felix Meschberger41cce522009-08-19 05:54:40 +00001073 callPlugins( properties, pid, sr, config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001074 }
1075 else
1076 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001077 // 104.5.3 ManagedService.updated must be called with null
1078 // if no configuration is available
Felix Meschberger41cce522009-08-19 05:54:40 +00001079 properties = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001080 }
1081
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001082 // update the service with the configuration
1083 try
1084 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001085 service.updated( properties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001086 }
1087 catch ( ConfigurationException ce )
1088 {
1089 if ( ce.getProperty() != null )
1090 {
1091 log( LogService.LOG_ERROR, sr + ": Updating configuration property " + ce.getProperty()
1092 + " caused a problem: " + ce.getReason(), ce );
1093 }
1094 else
1095 {
1096 log( LogService.LOG_ERROR, sr + ": Updating configuration caused a problem: " + ce.getReason(), ce );
1097
1098 }
1099 }
1100 catch ( Throwable t )
1101 {
1102 log( LogService.LOG_ERROR, sr + ": Unexpected problem updating configuration", t );
1103 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001104 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001105
Felix Meschberger432e3872008-03-07 14:58:57 +00001106 public String toString()
1107 {
1108 return "ManagedService Update: pid=" + pid;
1109 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001110 }
1111
1112 private class ManagedServiceFactoryUpdate implements Runnable
1113 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001114 private final String factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001115
Felix Meschberger41cce522009-08-19 05:54:40 +00001116 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001117
Felix Meschberger41cce522009-08-19 05:54:40 +00001118 private final ManagedServiceFactory service;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001119
Felix Meschberger41cce522009-08-19 05:54:40 +00001120 private final Factory factory;
1121
1122 private final Map configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001123
1124 ManagedServiceFactoryUpdate( String factoryPid, ServiceReference sr, ManagedServiceFactory service )
1125 {
1126 this.factoryPid = factoryPid;
1127 this.sr = sr;
1128 this.service = service;
Felix Meschberger41cce522009-08-19 05:54:40 +00001129
1130 Factory factory = null;
1131 Map configs = null;
1132 try
1133 {
1134 factory = getFactory( factoryPid );
1135 if (factory != null) {
1136 configs = new HashMap();
1137 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
1138 {
1139 final String pid = ( String ) pi.next();
1140 ConfigurationImpl cfg;
1141 try
1142 {
1143 cfg = getExistingConfiguration( pid );
1144 }
1145 catch ( IOException ioe )
1146 {
1147 log( LogService.LOG_ERROR, "Error loading configuration for " + pid, ioe );
1148 continue;
1149 }
1150
1151 // sanity check on the configuration
1152 if ( cfg == null )
1153 {
1154 log( LogService.LOG_ERROR, "Configuration " + pid + " referred to by factory " + factoryPid
1155 + " does not exist", null );
1156 factory.removePID( pid );
1157 factory.storeSilently();
1158 continue;
1159 }
1160 else if ( cfg.isNew() )
1161 {
1162 // Configuration has just been created but not yet updated
1163 // we currently just ignore it and have the update mechanism
1164 // provide the configuration to the ManagedServiceFactory
1165 // As of FELIX-612 (not storing new factory configurations)
1166 // this should not happen. We keep this for added stability
1167 // but raise the logging level to error.
1168 log( LogService.LOG_ERROR, "Ignoring new configuration pid=" + pid, null );
1169 continue;
1170 }
1171 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1172 {
1173 log( LogService.LOG_ERROR, "Configuration " + pid + " referred to by factory " + factoryPid
1174 + " seems to belong to factory " + cfg.getFactoryPid(), null );
1175 factory.removePID( pid );
1176 factory.storeSilently();
1177 continue;
1178 }
1179
1180 // get the configuration properties for later
1181 configs.put(cfg, cfg.getProperties( true ));
1182 }
1183 }
1184 }
1185 catch ( IOException ioe )
1186 {
1187 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID " + factoryPid, ioe );
1188 }
1189
1190 this.factory = factory;
1191 this.configs = configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001192 }
1193
1194
1195 public void run()
1196 {
Felix Meschberger41243192009-01-14 19:59:58 +00001197 Bundle serviceBundle = sr.getBundle();
1198 if ( serviceBundle == null )
1199 {
1200 log( LogService.LOG_INFO, "ManagedServiceFactory for factory PID " + factoryPid
1201 + " seems to already have been unregistered, not updating with factory", null );
1202 return;
1203 }
1204
Felix Meschberger41cce522009-08-19 05:54:40 +00001205 final String serviceBundleLocation = serviceBundle.getLocation();
1206 if ( !factory.tryBindLocation( serviceBundleLocation ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001207 {
1208 // factory PID is bound to another bundle
Felix Meschberger41cce522009-08-19 05:54:40 +00001209 log( LogService.LOG_ERROR, "Cannot use factory configuration " + factoryPid + " for "
1210 + ConfigurationManager.toString( sr ) + ": Configuration bound to bundle "
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001211 + factory.getBundleLocation(), null );
Felix Meschberger41cce522009-08-19 05:54:40 +00001212
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001213 return;
1214 }
1215
Felix Meschberger41cce522009-08-19 05:54:40 +00001216 for ( Iterator ci=configs.entrySet().iterator(); ci.hasNext(); )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001217 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001218 final Map.Entry entry = (Map.Entry) ci.next();
1219 final ConfigurationImpl cfg = (ConfigurationImpl) entry.getKey();
1220 final Dictionary properties = (Dictionary) entry.getValue();
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001221
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001222 // check bundle location of configuration
Felix Meschberger41cce522009-08-19 05:54:40 +00001223 if ( !cfg.tryBindLocation( serviceBundleLocation ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001224 {
1225 // configuration is bound to another bundle
Felix Meschberger41cce522009-08-19 05:54:40 +00001226 log( LogService.LOG_ERROR, "Cannot use configuration " + cfg.getPid() + " (factory " + factoryPid
1227 + ") for " + ConfigurationManager.toString( sr ) + ": Configuration bound to bundle "
1228 + cfg.getBundleLocation(), null );
1229
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001230 continue;
1231 }
1232
Felix Meschberger41cce522009-08-19 05:54:40 +00001233 // 104.3 Report an error in the log if more than one service
1234 // with the same PID asks for the configuration
1235 if ( cfg.getServiceReference() == null )
1236 {
1237 // assign the configuration to the service
1238 cfg.setServiceReference( sr );
1239 }
1240 else if ( !sr.equals( cfg.getServiceReference() ) )
1241 {
1242 log( LogService.LOG_ERROR, "Configuration for " + cfg.getPid() + " (factory " + factoryPid
1243 + ") has already been used for service "
1244 + ConfigurationManager.toString( cfg.getServiceReference() )
1245 + " and will now also be given to " + ConfigurationManager.toString( sr ), null );
1246 }
1247
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001248 // prepare the configuration for the service (call plugins)
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001249 // call the plugins with cm.target set to the service's factory PID
1250 // (clarification in Section 104.9.1 of Compendium 4.2)
Felix Meschberger41cce522009-08-19 05:54:40 +00001251 callPlugins( properties, factoryPid, sr, cfg );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001252
1253 // update the service with the configuration
1254 try
1255 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001256 // only, if there is non-null configuration data
Felix Meschberger41cce522009-08-19 05:54:40 +00001257 if ( properties != null )
Felix Meschberger2941ef92007-08-20 13:15:16 +00001258 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001259 log( LogService.LOG_DEBUG, sr + ": Updating configuration pid=" + cfg.getPid(), null );
1260 service.updated( cfg.getPid(), properties );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001261 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001262 }
1263 catch ( ConfigurationException ce )
1264 {
1265 if ( ce.getProperty() != null )
1266 {
1267 log( LogService.LOG_ERROR, sr + ": Updating configuration property " + ce.getProperty()
1268 + " caused a problem: " + ce.getReason(), ce );
1269 }
1270 else
1271 {
1272 log( LogService.LOG_ERROR, sr + ": Updating configuration caused a problem: " + ce.getReason(),
1273 ce );
1274
1275 }
1276 }
1277 catch ( Throwable t )
1278 {
1279 log( LogService.LOG_ERROR, sr + ": Unexpected problem updating configuration", t );
1280 }
1281 }
1282 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001283
1284
Felix Meschberger432e3872008-03-07 14:58:57 +00001285 public String toString()
1286 {
1287 return "ManagedServiceFactory Update: factoryPid=" + factoryPid;
1288 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001289 }
1290
1291 private class UpdateConfiguration implements Runnable
1292 {
1293
Felix Meschberger41cce522009-08-19 05:54:40 +00001294 private final ConfigurationImpl config;
Felix Meschberger41cce522009-08-19 05:54:40 +00001295 private final Dictionary properties;
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001296 private final boolean fireEvent;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001297
1298
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001299 UpdateConfiguration( final ConfigurationImpl config, boolean fireEvent )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001300 {
1301 this.config = config;
Felix Meschberger41cce522009-08-19 05:54:40 +00001302 this.properties = config.getProperties( true );
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001303 this.fireEvent = fireEvent;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001304 }
1305
1306
1307 public void run()
1308 {
1309 try
1310 {
1311 if ( config.getFactoryPid() == null )
1312 {
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001313 final ServiceReference[] srList = bundleContext.getServiceReferences( ManagedService.class
1314 .getName(), "(" + Constants.SERVICE_PID + "=" + config.getPid() + ")" );
Felix Meschberger41cce522009-08-19 05:54:40 +00001315 if ( srList != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001316 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001317 // find the primary configuration owner
1318 final ServiceReference ownerRef = getOwner( config, srList );
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001319 final String bundleLocation = ( ownerRef != null ) ? ownerRef.getBundle().getLocation()
1320 : config.getBundleLocation();
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001321
Felix Meschberger41cce522009-08-19 05:54:40 +00001322 // if the configuration is unbound, bind to owner
1323 if ( config.getBundleLocation() == null )
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001324 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001325 config.setDynamicBundleLocation( bundleLocation );
1326 }
1327 final String configBundleLocation = config.getBundleLocation();
1328
1329 // provide configuration to all services from the
1330 // correct bundle
1331 for ( int i = 0; i < srList.length; i++ )
1332 {
1333
1334 final ServiceReference userRef = srList[i];
1335 final String userRefLocation = userRef.getBundle().getLocation();
1336
1337 // only consider the entry if in the same bundle
1338 if ( !userRefLocation.equals( configBundleLocation ) )
1339 {
1340 log( LogService.LOG_ERROR, "Cannot use configuration " + config.getPid() + " for "
1341 + ConfigurationManager.toString( userRef ) + ": Configuration bound to bundle "
1342 + configBundleLocation, null );
1343
1344 continue;
1345 }
1346
1347 // 104.3 Report an error in the log if more than one
1348 // service with the same PID asks for the
1349 // configuration
1350 if ( userRef != ownerRef )
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001351 {
1352 log( LogService.LOG_ERROR, "Configuration for " + config.getPid()
Felix Meschberger41cce522009-08-19 05:54:40 +00001353 + " has already been used for service " + ConfigurationManager.toString( ownerRef )
1354 + " and will now also be given to " + ConfigurationManager.toString( userRef ), null );
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001355 }
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001356
Felix Meschberger41cce522009-08-19 05:54:40 +00001357 try
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001358 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001359 final ManagedService srv = ( ManagedService ) bundleContext.getService( userRef );
1360 if ( srv != null )
1361 {
1362 Dictionary props = new CaseInsensitiveDictionary( properties );
1363 callPlugins( props, config.getPid(), userRef, config );
1364 srv.updated( props );
1365 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001366 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001367 finally
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001368 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001369 bundleContext.ungetService( userRef );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001370 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001371 }
1372 }
1373 }
1374 else
1375 {
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001376 ServiceReference[] srList = bundleContext.getServiceReferences( ManagedServiceFactory.class
1377 .getName(), "(" + Constants.SERVICE_PID + "=" + config.getFactoryPid() + ")" );
1378 if ( srList != null && srList.length > 0 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001379 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001380 // find the primary configuration owner
1381 final ServiceReference ownerRef = getOwner( config, srList );
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001382 final String bundleLocation = ( ownerRef != null ) ? ownerRef.getBundle().getLocation()
1383 : config.getBundleLocation();
Felix Meschberger41cce522009-08-19 05:54:40 +00001384
1385 // if the configuration is unbound, bind to owner
1386 if ( config.getBundleLocation() == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001387 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001388 config.setDynamicBundleLocation( bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001389 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001390
1391 // provide configuration to all services from the
1392 // correct bundle
1393 for ( int i = 0; i < srList.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001394 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001395 final ServiceReference ref = srList[i];
1396 final String refLocation = ref.getBundle().getLocation();
1397
1398 // only consider the entry if in the same bundle
1399 if ( !refLocation.equals( config.getBundleLocation() ) )
1400 {
1401 log( LogService.LOG_ERROR, "Cannot use configuration " + config.getPid() + " (factory "
1402 + config.getFactoryPid() + ") for " + ConfigurationManager.toString( ref )
1403 + ": Configuration bound to bundle " + config.getBundleLocation(), null );
1404
1405 continue;
1406 }
1407
1408 // 104.3 Report an error in the log if more than one
1409 // service with the same PID asks for the
1410 // configuration
1411 if ( ref != ownerRef )
1412 {
1413 log( LogService.LOG_ERROR, "Configuration for " + config.getPid() + " (factory "
1414 + config.getFactoryPid() + ") has already been used for service "
1415 + ConfigurationManager.toString( ownerRef ) + " and will now also be given to "
1416 + ConfigurationManager.toString( ref ), null );
1417 }
1418
1419 try
1420 {
1421 final ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext
1422 .getService( ref );
1423 if ( srv != null && properties != null )
1424 {
1425 Dictionary props = new CaseInsensitiveDictionary( properties );
1426 callPlugins( props, config.getFactoryPid(), ref, config );
1427 srv.updated( config.getPid(), props );
1428 }
1429 }
1430 finally
1431 {
1432 bundleContext.ungetService( ref );
1433 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001434 }
1435 }
1436 }
1437 }
1438 catch ( ConfigurationException ce )
1439 {
1440 if ( ce.getProperty() != null )
1441 {
1442 log( LogService.LOG_ERROR, "Updating configuration property " + ce.getProperty()
1443 + " caused a problem: " + ce.getReason(), ce );
1444 }
1445 else
1446 {
1447 log( LogService.LOG_ERROR, "Updating configuration caused a problem: " + ce.getReason(), ce );
1448
1449 }
1450 }
1451 catch ( Throwable t )
1452 {
1453 log( LogService.LOG_ERROR, "Unexpected problem updating configuration", t );
1454 }
Felix Meschberger15e1c6f2009-08-18 07:52:13 +00001455 finally
1456 {
1457 // the update event has to be sent regardless of whether the
1458 // configuration was updated in a managed service or not
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001459 if ( fireEvent )
1460 {
1461 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPid(), config.getFactoryPid() );
1462 }
Felix Meschberger15e1c6f2009-08-18 07:52:13 +00001463 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001464 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001465
Felix Meschberger41cce522009-08-19 05:54:40 +00001466
1467 private ServiceReference getOwner( ConfigurationImpl config, ServiceReference[] srList )
1468 {
1469 // find the current owner among the references (if any)
1470 if ( config.getServiceReference() != null )
1471 {
1472 for ( int i = 0; i < srList.length; i++ )
1473 {
1474 if ( srList[i].equals( config.getServiceReference() ) )
1475 {
1476 return srList[i];
1477 }
1478 }
1479 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001480 // configuration has never been supplied or the binding is stale
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001481
1482 // if the configuration is location bound, find a service reference
1483 // from the same bundle
1484 final String configLocation = config.getBundleLocation();
1485 if (configLocation != null) {
1486 for ( int i = 0; i < srList.length; i++ )
1487 {
1488 if ( configLocation.equals(srList[i].getBundle().getLocation() ) )
1489 {
1490 return srList[i];
1491 }
1492 }
1493 // no service from the same bundle found, thus we cannot
1494 // find a new owner !!
1495 return null;
1496 }
1497 // configuration is not location bound (yet)
1498
Felix Meschberger41cce522009-08-19 05:54:40 +00001499 // just use the first entry in the list as the new owner
1500 final ServiceReference ownerRef = srList[0];
1501 config.setServiceReference( ownerRef );
1502 return ownerRef;
1503 }
1504
1505
Felix Meschberger432e3872008-03-07 14:58:57 +00001506 public String toString()
1507 {
1508 return "Update: pid=" + config.getPid();
1509 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001510 }
1511
1512 private class DeleteConfiguration implements Runnable
1513 {
Felix Meschberger66423332007-08-22 08:46:34 +00001514
Felix Meschbergerc12db8c2009-08-19 06:43:59 +00001515 private final String pid;
1516 private final String factoryPid;
1517 private final String configLocation;
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001518 private final boolean fireEvent;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001519
1520
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001521 DeleteConfiguration( ConfigurationImpl config, boolean fireEvent )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001522 {
Felix Meschberger66423332007-08-22 08:46:34 +00001523 this.pid = config.getPid();
1524 this.factoryPid = config.getFactoryPid();
Felix Meschbergerc12db8c2009-08-19 06:43:59 +00001525 this.configLocation = config.getBundleLocation();
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001526 this.fireEvent = fireEvent;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001527 }
1528
1529
1530 public void run()
1531 {
1532 try
1533 {
Felix Meschberger66423332007-08-22 08:46:34 +00001534 if ( factoryPid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001535 {
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001536 ServiceReference[] srList = bundleContext.getServiceReferences( ManagedService.class.getName(), "("
Felix Meschberger66423332007-08-22 08:46:34 +00001537 + Constants.SERVICE_PID + "=" + pid + ")" );
Felix Meschberger41cce522009-08-19 05:54:40 +00001538 if ( srList != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001539 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001540 for ( int i = 0; i < srList.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001541 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001542 final ServiceReference sr = srList[i];
1543 if ( sr.getBundle().getLocation().equals( configLocation ) )
1544 {
1545 // only if the service is from the bound bundle
1546 final ManagedService srv = ( ManagedService ) bundleContext.getService( sr );
1547 try
1548 {
1549 srv.updated( null );
1550 }
1551 finally
1552 {
1553 bundleContext.ungetService( sr );
1554 }
1555 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001556 }
1557 }
1558 }
1559 else
1560 {
1561 // remove the pid from the factory
Felix Meschberger66423332007-08-22 08:46:34 +00001562 Factory factory = getFactory( factoryPid );
1563 factory.removePID( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001564 factory.store();
1565
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +00001566 ServiceReference[] srList = bundleContext.getServiceReferences( ManagedServiceFactory.class
1567 .getName(), "(" + Constants.SERVICE_PID + "=" + factoryPid + ")" );
Felix Meschberger41cce522009-08-19 05:54:40 +00001568 if ( srList != null)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001569 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001570 for ( int i = 0; i < srList.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001571 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001572 final ServiceReference sr = srList[i];
1573 if ( sr.getBundle().getLocation().equals( configLocation ) )
1574 {
1575 // only if the service is from the bound bundle
1576 final ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext
1577 .getService( sr );
1578 try
1579 {
1580 srv.deleted( pid );
1581 }
1582 finally
1583 {
1584 bundleContext.ungetService( sr );
1585 }
1586 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001587 }
1588 }
1589 }
1590 }
1591 catch ( ConfigurationException ce )
1592 {
1593 if ( ce.getProperty() != null )
1594 {
1595 log( LogService.LOG_ERROR, "Updating configuration property " + ce.getProperty()
1596 + " caused a problem: " + ce.getReason(), ce );
1597 }
1598 else
1599 {
1600 log( LogService.LOG_ERROR, "Updating configuration caused a problem: " + ce.getReason(), ce );
1601
1602 }
1603 }
1604 catch ( Throwable t )
1605 {
1606 log( LogService.LOG_ERROR, "Unexpected problem updating configuration", t );
1607 }
Felix Meschberger15e1c6f2009-08-18 07:52:13 +00001608 finally
1609 {
1610 // the delete event has to be sent regardless of whether the
1611 // configuration was updated in a managed service or not
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001612 if ( fireEvent )
1613 {
1614 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, pid, factoryPid );
1615 }
Felix Meschberger15e1c6f2009-08-18 07:52:13 +00001616 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001617 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001618
Felix Meschberger432e3872008-03-07 14:58:57 +00001619 public String toString()
1620 {
1621 return "Delete: pid=" + pid;
1622 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001623 }
1624
1625 private class FireConfigurationEvent implements Runnable
1626 {
1627 private int type;
1628
Felix Meschberger66423332007-08-22 08:46:34 +00001629 private String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001630
Felix Meschberger66423332007-08-22 08:46:34 +00001631 private String factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001632
1633
Felix Meschberger66423332007-08-22 08:46:34 +00001634 FireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001635 {
1636 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001637 this.pid = pid;
1638 this.factoryPid = factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001639 }
1640
1641
1642 public void run()
1643 {
1644 // get the listeners
1645 ServiceReference[] srs = configurationListenerTracker.getServiceReferences();
1646 if ( srs == null || srs.length == 0 )
1647 {
1648 return;
1649 }
1650
Felix Meschbergerb4f83e42009-01-15 08:53:36 +00001651 ConfigurationEvent event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001652
1653 for ( int i = 0; i < srs.length; i++ )
1654 {
1655 ConfigurationListener cl = ( ConfigurationListener ) configurationListenerTracker.getService( srs[i] );
1656 try
1657 {
1658 cl.configurationEvent( event );
1659 }
1660 catch ( Throwable t )
1661 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001662 log( LogService.LOG_ERROR, "Unexpected problem delivery configuration event to "
1663 + ConfigurationManager.toString( srs[i] ), t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001664 }
1665 }
1666 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001667
Felix Meschberger432e3872008-03-07 14:58:57 +00001668 public String toString()
1669 {
1670 return "Fire ConfigurationEvent: pid=" + pid;
1671 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001672 }
1673
Felix Meschberger41cce522009-08-19 05:54:40 +00001674 private static class ManagedServiceTracker extends ServiceTracker
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001675 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001676
Felix Meschberger41cce522009-08-19 05:54:40 +00001677 private final ConfigurationManager cm;
1678
1679
1680 ManagedServiceTracker( ConfigurationManager cm )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001681 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001682 super( cm.bundleContext, ManagedService.class.getName(), null );
Carsten Ziegeler41683982007-12-27 08:35:27 +00001683 this.cm = cm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001684 open();
1685 }
1686
1687
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001688 public Object addingService( ServiceReference reference )
1689 {
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001690 Object serviceObject = super.addingService( reference );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001691
1692 // configure the managed service
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001693 if ( serviceObject instanceof ManagedService )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001694 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001695 cm.configure(reference, ( ManagedService ) serviceObject);
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001696 }
1697 else
1698 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001699 cm.log( LogService.LOG_WARNING, "Service " + serviceObject + " is not a ManagedService", null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001700 }
1701
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001702 return serviceObject;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001703 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001704
1705
1706 public void removedService( ServiceReference reference, Object service )
1707 {
1708 // check whether we can take back the configuration object
1709 String[] pids = getServicePid( reference );
1710 if ( pids != null )
1711 {
1712 for ( int i = 0; i < pids.length; i++ )
1713 {
1714 ConfigurationImpl cfg = cm.getCachedConfiguration( pids[i] );
1715 if ( cfg != null && reference.equals( cfg.getServiceReference() ) )
1716 {
1717 cfg.setServiceReference( null );
1718 }
1719 }
1720 }
1721
1722 super.removedService( reference, service );
1723 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001724 }
1725
Felix Meschberger41cce522009-08-19 05:54:40 +00001726 private static class ManagedServiceFactoryTracker extends ServiceTracker
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001727 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001728 private final ConfigurationManager cm;
1729
1730
1731 ManagedServiceFactoryTracker( ConfigurationManager cm )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001732 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001733 super( cm.bundleContext, ManagedServiceFactory.class.getName(), null );
1734 this.cm = cm;
1735 open();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001736 }
1737
1738
1739 public Object addingService( ServiceReference reference )
1740 {
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001741 Object serviceObject = super.addingService( reference );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001742
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001743 // configure the managed service factory
1744 if ( serviceObject instanceof ManagedServiceFactory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001745 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001746 cm.configure( reference, ( ManagedServiceFactory ) serviceObject );
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001747 }
1748 else
1749 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001750 cm.log( LogService.LOG_WARNING, "Service " + serviceObject + " is not a ManagedServiceFactory", null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001751 }
1752
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001753 return serviceObject;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001754 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001755
Felix Meschberger6a698df2009-08-16 18:38:46 +00001756
Felix Meschbergerf4631322008-03-10 12:32:35 +00001757 public void removedService( ServiceReference reference, Object service )
1758 {
1759 // check whether we can take back the configuration objects
Felix Meschberger851c6412009-08-16 18:43:26 +00001760 String[] factoryPids = getServicePid( reference );
1761 if ( factoryPids != null )
Felix Meschbergerf4631322008-03-10 12:32:35 +00001762 {
Felix Meschberger851c6412009-08-16 18:43:26 +00001763 for ( int i = 0; i < factoryPids.length; i++ )
1764 {
1765 Factory factory = cm.getCachedFactory( factoryPids[i] );
Felix Meschberger6a698df2009-08-16 18:38:46 +00001766 if ( factory != null )
Felix Meschbergerf4631322008-03-10 12:32:35 +00001767 {
Felix Meschberger6a698df2009-08-16 18:38:46 +00001768 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
Felix Meschbergerf4631322008-03-10 12:32:35 +00001769 {
Felix Meschberger6a698df2009-08-16 18:38:46 +00001770 String pid = ( String ) pi.next();
1771 ConfigurationImpl cfg = cm.getCachedConfiguration( pid );
Felix Meschberger41cce522009-08-19 05:54:40 +00001772 if ( cfg != null && reference.equals( cfg.getServiceReference() ) )
Felix Meschberger6a698df2009-08-16 18:38:46 +00001773 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001774 cfg.setServiceReference( null );
Felix Meschberger6a698df2009-08-16 18:38:46 +00001775 }
Felix Meschbergerf4631322008-03-10 12:32:35 +00001776 }
1777 }
1778 }
Felix Meschberger851c6412009-08-16 18:43:26 +00001779 }
Felix Meschbergerf4631322008-03-10 12:32:35 +00001780
1781 super.removedService( reference, service );
1782 }
1783
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001784 }
1785}