blob: f129642d236ebcd39668448894e6884f0ab5ad49 [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
138 private Map factories;
139
140 // the cache of Configuration instances mapped by their PID
141 private Map configurations;
142
Felix Meschberger08282c32009-01-28 07:01:55 +0000143 // the maximum log level when no LogService is available
144 private int logLevel = CM_LOG_LEVEL_DEFAULT;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000145
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000146 // flag indicating whether BundleChange events should be consumed (FELIX-979)
147 private volatile boolean handleBundleEvents;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000148
149 public void start( BundleContext bundleContext )
150 {
151 // track the log service using a ServiceTracker
Felix Meschberger85b355d2007-08-31 07:17:38 +0000152 logTracker = new ServiceTracker( bundleContext, LOG_SERVICE_NAME , null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000153 logTracker.open();
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000154
Felix Meschberger08282c32009-01-28 07:01:55 +0000155 // assign the log level
156 String logLevelProp = bundleContext.getProperty( CM_LOG_LEVEL );
157 if ( logLevelProp == null )
158 {
159 logLevel = CM_LOG_LEVEL_DEFAULT;
160 }
161 else
162 {
163 try
164 {
165 logLevel = Integer.parseInt( logLevelProp );
166 }
167 catch ( NumberFormatException nfe )
168 {
169 logLevel = CM_LOG_LEVEL_DEFAULT;
170 }
171 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000172
173 // set up some fields
174 this.bundleContext = bundleContext;
175 this.factories = new HashMap();
176 this.configurations = new HashMap();
177
178 // configurationlistener support
179 configurationListenerTracker = new ServiceTracker( bundleContext, ConfigurationListener.class.getName(), null );
180 configurationListenerTracker.open();
181
182 // initialize the asynchonous updater thread
183 this.updateThread = new UpdateThread( this );
184 this.updateThread.start();
185
186 // set up the location (might throw IllegalArgumentException)
187 try
188 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000189 FilePersistenceManager fpm = new FilePersistenceManager( bundleContext, bundleContext
190 .getProperty( CM_CONFIG_DIR ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000191 Hashtable props = new Hashtable();
192 props.put( Constants.SERVICE_PID, fpm.getClass().getName() );
193 props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
194 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
195 props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
196 bundleContext.registerService( PersistenceManager.class.getName(), fpm, props );
197 }
198 catch ( IllegalArgumentException iae )
199 {
200 log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
201 }
202
203 // register as bundle and service listener
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000204 handleBundleEvents = true;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000205 bundleContext.addBundleListener( this );
206
207 // get all persistence managers to begin with
208 pmtCount = 1; // make sure to get the persistence managers at least
209 // once
210 persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
211 persistenceManagerTracker.open();
212
213 // create and register configuration admin - start after PM tracker ...
214 ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
215 Hashtable props = new Hashtable();
216 props.put( Constants.SERVICE_PID, "org.apache.felix.cm.ConfigurationAdmin" );
217 props.put( Constants.SERVICE_DESCRIPTION, "Configuration Admin Service Specification 1.2 Implementation" );
218 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000219 configurationAdminRegistration = bundleContext.registerService( ConfigurationAdmin.class.getName(), caf, props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000220
221 // start handling ManagedService[Factory] services
Carsten Ziegeler41683982007-12-27 08:35:27 +0000222 managedServiceTracker = new ManagedServiceTracker(this);
223 managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this);
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000224 }
225
226
227 public void stop( BundleContext bundleContext )
228 {
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000229
230 // immediately unregister the Configuration Admin before cleaning up
Felix Meschberger10568352009-01-15 08:57:11 +0000231 // clearing the field before actually unregistering the service
232 // prevents IllegalStateException in getServiceReference() if
233 // the field is not null but the service already unregistered
234 if (configurationAdminRegistration != null) {
235 ServiceRegistration reg = configurationAdminRegistration;
236 configurationAdminRegistration = null;
237 reg.unregister();
238 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000239
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000240 // stop handling ManagedService[Factory] services
241 managedServiceFactoryTracker.close();
242 managedServiceTracker.close();
243
244 // don't care for PersistenceManagers any more
245 persistenceManagerTracker.close();
246
247 // stop listening for events
248 bundleContext.removeBundleListener( this );
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000249 handleBundleEvents = false;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000250
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
277 this.bundleContext = null;
278 this.configurations = null;
279 }
280
281
282 // ---------- Configuration caching support --------------------------------
283
284 ConfigurationImpl getCachedConfiguration( String pid )
285 {
286 synchronized ( configurations )
287 {
288 return ( ConfigurationImpl ) configurations.get( pid );
289 }
290 }
291
292
293 Iterator getCachedConfigurations()
294 {
295 synchronized ( configurations )
296 {
297 return configurations.values().iterator();
298 }
299 }
300
301
Felix Meschberger2941ef92007-08-20 13:15:16 +0000302 ConfigurationImpl cacheConfiguration( ConfigurationImpl configuration )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000303 {
304 synchronized ( configurations )
305 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000306 Object existing = configurations.get( configuration.getPid() );
307 if ( existing != null )
308 {
309 return ( ConfigurationImpl ) existing;
310 }
311
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000312 configurations.put( configuration.getPid(), configuration );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000313 return configuration;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000314 }
315 }
316
317
318 void removeConfiguration( ConfigurationImpl configuration )
319 {
320 synchronized ( configurations )
321 {
322 configurations.remove( configuration.getPid() );
323 }
324 }
325
326
327 // ---------- ConfigurationAdminImpl support -------------------------------
328
329 /*
330 * (non-Javadoc)
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000331 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000332 * @see org.osgi.service.cm.ConfigurationAdmin#createFactoryConfiguration(java.lang.String)
333 */
334 ConfigurationImpl createFactoryConfiguration( ConfigurationAdminImpl configurationAdmin, String factoryPid )
335 throws IOException
336 {
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000337 // check Persmission if factory is bound to another bundle
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000338 Factory factory = getFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000339 if ( factory.getBundleLocation() != null
340 && !factory.getBundleLocation().equals( configurationAdmin.getBundle().getLocation() ) )
341 {
342 configurationAdmin.checkPermission();
343 }
344
345 // create the configuration
346 String pid = createPid( factoryPid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000347 ConfigurationImpl config = createConfiguration( pid, factoryPid, configurationAdmin.getBundle().getLocation() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000348
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000349 return config;
350 }
351
352
353 /*
354 * (non-Javadoc)
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000355 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000356 * @see org.osgi.service.cm.ConfigurationAdmin#createFactoryConfiguration(java.lang.String,
357 * java.lang.String)
358 */
359 ConfigurationImpl createFactoryConfiguration( String factoryPid, String location ) throws IOException
360 {
361 // create the configuration
362 String pid = createPid( factoryPid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000363 ConfigurationImpl config = createConfiguration( pid, factoryPid, location );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000364
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000365 return config;
366 }
367
368
Felix Meschberger2941ef92007-08-20 13:15:16 +0000369 ConfigurationImpl getExistingConfiguration( String pid ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000370 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000371 ConfigurationImpl config = getCachedConfiguration( pid );
372 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000373 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000374 return config;
375 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000376
Felix Meschberger2941ef92007-08-20 13:15:16 +0000377 PersistenceManager[] pmList = getPersistenceManagers();
378 for ( int i = 0; i < pmList.length; i++ )
379 {
380 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000381 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000382 Dictionary props = pmList[i].load( pid );
383 config = new ConfigurationImpl( this, pmList[i], props );
384 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000385 }
386 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000387
Felix Meschberger2941ef92007-08-20 13:15:16 +0000388 // neither the cache nor any persistence manager has configuration
389 return null;
390 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000391
392
Felix Meschberger2941ef92007-08-20 13:15:16 +0000393 ConfigurationImpl getConfiguration( String pid, String bundleLocation ) throws IOException
394 {
395 // check for existing (cached or persistent) configuration
396 ConfigurationImpl config = getExistingConfiguration( pid );
397 if ( config != null )
398 {
399 return config;
400 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000401
Felix Meschberger2941ef92007-08-20 13:15:16 +0000402 // else create new configuration also setting the bundle location
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000403 // and cache the new configuration
404 config = createConfiguration( pid, null, bundleLocation );
405 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000406 }
407
408
409 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
410 throws IOException, InvalidSyntaxException
411 {
412 Filter filter = null;
413 if ( filterString != null )
414 {
415 filter = bundleContext.createFilter( filterString );
416 }
417
418 boolean unprivileged = configurationAdmin != null && !configurationAdmin.hasPermission();
419 String location = unprivileged ? configurationAdmin.getBundle().getLocation() : null;
420
421 List configList = new ArrayList();
422
423 PersistenceManager[] pmList = getPersistenceManagers();
424 for ( int i = 0; i < pmList.length; i++ )
425 {
426 Enumeration configs = pmList[i].getDictionaries();
427 while ( configs.hasMoreElements() )
428 {
429 Dictionary config = ( Dictionary ) configs.nextElement();
430
431 // ignore non-Configuration dictionaries
Felix Meschberger86a0d172007-07-04 07:15:01 +0000432 String pid = ( String ) config.get( Constants.SERVICE_PID );
433 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000434 {
435 continue;
436 }
437
438 // ignore this config if not privileged and not bound to bundle
439 if ( unprivileged )
440 {
441 Object boundLocation = config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION );
442 if ( !location.equals( boundLocation ) )
443 {
444 continue;
445 }
446 }
447
448 // check filter
449 if ( filter == null || filter.match( config ) )
450 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000451 // ensure the service.pid and returned a cached config if available
452 ConfigurationImpl cfg = getCachedConfiguration( pid );
453 if ( cfg == null )
454 {
455 cfg = new ConfigurationImpl( this, pmList[i], config );
456 }
457
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000458 // FELIX-611: Ignore configuration objects without props
459 if ( !cfg.isNew() )
460 {
461 configList.add( cfg );
462 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000463 }
464 }
465 }
466
Felix Meschberger8faceff2007-07-04 07:19:48 +0000467 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000468 .size()] );
469 }
470
471
472 void deleted( ConfigurationImpl config )
473 {
474 // remove the configuration from the cache
475 removeConfiguration( config );
476 updateThread.schedule( new DeleteConfiguration( config ) );
477 }
478
479
480 void updated( ConfigurationImpl config )
481 {
482 updateThread.schedule( new UpdateConfiguration( config ) );
483 }
484
485
Felix Meschberger66423332007-08-22 08:46:34 +0000486 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000487 {
488
Felix Meschberger66423332007-08-22 08:46:34 +0000489 updateThread.schedule( new FireConfigurationEvent( type, pid, factoryPid) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000490 }
491
492
493 // ---------- BundleListener -----------------------------------------------
494
495 public void bundleChanged( BundleEvent event )
496 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000497 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000498 {
499 String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000500
501 try
502 {
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000503 PersistenceManager[] pmList = getPersistenceManagers();
504 for ( int i = 0; i < pmList.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000505 {
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000506 Enumeration configs = pmList[i].getDictionaries();
507 while ( configs.hasMoreElements() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000508 {
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000509 Dictionary config = ( Dictionary ) configs.nextElement();
510
511 String pid = ( String ) config.get( Constants.SERVICE_PID );
512 if ( pid != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000513 {
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000514 ConfigurationImpl cfg = getCachedConfiguration( pid );
515 if ( cfg == null )
516 {
517 cfg = new ConfigurationImpl( this, pmList[i], config );
518 }
519
520 if ( location.equals( cfg.getBundleLocation() ) )
521 {
522 cfg.setBundleLocation( null );
523 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000524 }
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000525 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000526 {
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000527
528 Factory factory = Factory.getFactory( pmList[i], config );
529 if ( factory != null )
530 {
Felix Meschbergerf4631322008-03-10 12:32:35 +0000531 Factory cachedFactory = getCachedFactory( factory.getFactoryPid() );
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000532 if ( cachedFactory != null )
533 {
534 factory = cachedFactory;
535 }
536
537 if ( location.equals( factory.getBundleLocation() ) )
538 {
539 factory.setBundleLocation( null );
540 }
541 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000542 }
543 }
544 }
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000545
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000546 }
547 catch ( Exception e )
548 {
549 log( LogService.LOG_WARNING, "Problem unbinding configurations for bundle " + location, e );
550 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000551 }
552 }
553
554
555 // ---------- internal -----------------------------------------------------
556
557 private PersistenceManager[] getPersistenceManagers()
558 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000559 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
560 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000561 {
562
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000563 PersistenceManager[] pm;
564
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000565 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
566 if ( refs == null || refs.length == 0 )
567 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000568 pm = new PersistenceManager[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000569 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000570 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000571 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000572 // sort the references according to the cmRanking property
573 SortedSet pms = new TreeSet( new RankingComparator( false ) );
574 for ( int i = 0; i < refs.length; i++ )
575 {
576 pms.add( refs[i] );
577 }
578
579 // create the service array from the sorted set of referenecs
580 pm = new PersistenceManager[pms.size()];
581 int pmIndex = 0;
582 for ( Iterator pi = pms.iterator(); pi.hasNext(); pmIndex++)
583 {
584 ServiceReference ref = ( ServiceReference ) pi.next();
585 pm[pmIndex] = ( PersistenceManager ) persistenceManagerTracker.getService( ref );
586 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000587 }
588
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000589 pmtCount = currentPmtCount;
590 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000591 }
592
593 return persistenceManagers;
594 }
595
596
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000597 private ServiceReference getServiceReference()
598 {
599 ServiceRegistration reg = configurationAdminRegistration;
600 return ( reg != null ) ? reg.getReference() : null;
601 }
602
603
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000604 private void configure( ServiceReference sr, ManagedService service )
605 {
606 String pid = ( String ) sr.getProperty( Constants.SERVICE_PID );
607 if ( pid != null )
608 {
609 ManagedServiceUpdate update = new ManagedServiceUpdate( pid, sr, service );
610 updateThread.schedule( update );
611 }
612
613 }
614
615
616 private void configure( ServiceReference sr, ManagedServiceFactory service )
617 {
618 String pid = ( String ) sr.getProperty( Constants.SERVICE_PID );
619 if ( pid != null )
620 {
621 ManagedServiceFactoryUpdate update = new ManagedServiceFactoryUpdate( pid, sr, service );
622 updateThread.schedule( update );
623 }
624
625 }
626
627
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000628 /**
629 * Factory method to create a new configuration object. The configuration
630 * object returned is not stored in configuration cache and only persisted
631 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000632 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000633 * @param pid
634 * The PID of the new configuration object. Must not be
635 * <code>null</code>.
636 * @param factoryPid
637 * The factory PID of the new configuration. Not
638 * <code>null</code> if the new configuration object belongs to
639 * a factory. The configuration object will not be persisted if
640 * this parameter is not <code>null</code>.
641 * @param bundleLocation
642 * The bundle location of the bundle to which the configuration
643 * belongs or <code>null</code> if the configuration is not
644 * bound yet.
645 * @return The new configuration object
646 * @throws IOException
647 * May be thrown if an error occurrs persisting the new
648 * configuration object.
649 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000650 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000651 {
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000652 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000653 }
654
655
Felix Meschbergerf4631322008-03-10 12:32:35 +0000656 Factory getCachedFactory( String factoryPid )
657 {
658 synchronized ( factories )
659 {
660 return ( Factory ) factories.get( factoryPid );
661 }
662 }
663
664
665 void cacheFactory( Factory factory )
666 {
667 synchronized ( factories )
668 {
669 factories.put( factory.getFactoryPid(), factory );
670 }
671 }
672
673
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000674 Factory getFactory( String factoryPid ) throws IOException
675 {
Felix Meschbergerf4631322008-03-10 12:32:35 +0000676 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000677 if ( factory != null )
678 {
679 return factory;
680 }
681
682 PersistenceManager[] pmList = getPersistenceManagers();
683 for ( int i = 0; i < pmList.length; i++ )
684 {
685 if ( Factory.exists( pmList[i], factoryPid ) )
686 {
687 factory = Factory.load( pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000688 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000689 return factory;
690 }
691 }
692
693 // if getting here, there is no configuration yet, optionally create new
694 return createFactory( factoryPid );
695 }
696
697
698 Factory createFactory( String factoryPid )
699 {
700 Factory factory = new Factory( getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000701 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000702 return factory;
703 }
704
705
Felix Meschberger2941ef92007-08-20 13:15:16 +0000706 /**
707 * Calls the registered configuration plugins on the given configuration
708 * object unless the configuration has just been created and not been
709 * updated yet.
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000710 *
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000711 * @param targetPid The identification of the configuration update used to
712 * select the plugins according to their cm.target service
713 * property
Felix Meschberger2941ef92007-08-20 13:15:16 +0000714 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000715 * is to be updated with configuration
Felix Meschberger2941ef92007-08-20 13:15:16 +0000716 * @param cfg The configuration object whose properties have to be passed
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000717 * through the plugins
Felix Meschberger2941ef92007-08-20 13:15:16 +0000718 * @return The properties from the configuration object passed through the
719 * plugins or <code>null</code> if the configuration object has
720 * been newly created and no properties exist yet.
721 */
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000722 private Dictionary callPlugins( final String targetPid, final ServiceReference sr, final ConfigurationImpl cfg )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000723 {
Felix Meschbergera0903df2009-01-19 10:40:28 +0000724 // return a deep copy, since the plugins may tamper with the array
725 // and collection elements, which should not modify the internal data
726 Dictionary props = cfg.getProperties( true );
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000727
Felix Meschberger2941ef92007-08-20 13:15:16 +0000728 // guard against NPE for new configuration never updated
729 if (props == null) {
730 return null;
731 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000732
733 ServiceReference[] plugins = null;
734 try
735 {
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000736 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000737 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000738 }
739 catch ( InvalidSyntaxException ise )
740 {
741 // no filter, no exception ...
742 }
743
744 // abort early if there are no plugins
745 if ( plugins == null || plugins.length == 0 )
746 {
747 return props;
748 }
749
750 // sort the plugins by their service.cmRanking
751 SortedSet pluginSet = new TreeSet( cmRankComp );
Carsten Ziegeler7853b9a2008-01-11 16:30:24 +0000752 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000753 {
754 pluginSet.add( plugins[i] );
755 }
756
757 // call the plugins in order
758 for ( Iterator pi = pluginSet.iterator(); pi.hasNext(); )
759 {
760 ServiceReference pluginRef = ( ServiceReference ) pi.next();
761 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
762 try
763 {
764 plugin.modifyConfiguration( sr, props );
765 }
766 catch ( Throwable t )
767 {
768 log( LogService.LOG_ERROR, "Unexpected problem calling" + " configuration plugin", t );
769 }
770 finally
771 {
772 // ensure ungetting the plugin
773 bundleContext.ungetService( pluginRef );
774 }
775 cfg.setAutoProperties( props, false );
776 }
777
778 return props;
779 }
780
781
782 /**
783 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000784 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000785 * @param factoryPid
786 * @return
787 */
788 private static String createPid( String factoryPid )
789 {
790 SecureRandom ng = numberGenerator;
791 if ( ng == null )
792 {
793 numberGenerator = ng = new SecureRandom();
794 }
795
796 byte[] randomBytes = new byte[16];
797 ng.nextBytes( randomBytes );
798 randomBytes[6] &= 0x0f; /* clear version */
799 randomBytes[6] |= 0x40; /* set to version 4 */
800 randomBytes[8] &= 0x3f; /* clear variant */
801 randomBytes[8] |= 0x80; /* set to IETF variant */
802
803 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
804
805 // prefix the new pid with the factory pid
806 buf.append( factoryPid ).append( "." );
807
808 // serialize the UUID into the buffer
809 for ( int i = 0; i < randomBytes.length; i++ )
810 {
811
812 if ( i == 4 || i == 6 || i == 8 || i == 10 )
813 {
814 buf.append( '-' );
815 }
816
817 int val = randomBytes[i] & 0xff;
818 buf.append( Integer.toHexString( val >> 4 ) );
819 buf.append( Integer.toHexString( val & 0xf ) );
820 }
821
822 return buf.toString();
823 }
824
825
826 void log( int level, String message, Throwable t )
827 {
Felix Meschberger08282c32009-01-28 07:01:55 +0000828 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +0000829 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000830 if ( log != null )
831 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000832 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000833 return;
834 }
835
Felix Meschberger08282c32009-01-28 07:01:55 +0000836 // Otherwise only log if more serious than the configured level
837 if ( level <= logLevel )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000838 {
Felix Meschberger08282c32009-01-28 07:01:55 +0000839 String code;
840 switch ( level )
841 {
842 case LogService.LOG_INFO:
843 code = "*INFO *";
844 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000845
Felix Meschberger08282c32009-01-28 07:01:55 +0000846 case LogService.LOG_WARNING:
847 code = "*WARN *";
848 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000849
Felix Meschberger08282c32009-01-28 07:01:55 +0000850 case LogService.LOG_ERROR:
851 code = "*ERROR*";
852 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000853
Felix Meschberger08282c32009-01-28 07:01:55 +0000854 case LogService.LOG_DEBUG:
855 default:
856 code = "*DEBUG*";
857 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000858
Felix Meschberger08282c32009-01-28 07:01:55 +0000859 System.err.println( code + " " + message );
860 if ( t != null )
861 {
862 t.printStackTrace( System.err );
863 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000864 }
865 }
866
867 // ---------- inner classes ------------------------------------------------
868
869 private class ManagedServiceUpdate implements Runnable
870 {
871 private String pid;
872
873 private ServiceReference sr;
874
875 private ManagedService service;
876
877
878 ManagedServiceUpdate( String pid, ServiceReference sr, ManagedService service )
879 {
880 this.pid = pid;
881 this.sr = sr;
882 this.service = service;
883 }
884
885
886 public void run()
887 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000888 // get or load configuration for the pid
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000889 ConfigurationImpl cfg;
890 try
891 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000892 cfg = getExistingConfiguration( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000893 }
894 catch ( IOException ioe )
895 {
896 log( LogService.LOG_ERROR, "Error loading configuration for " + pid, ioe );
897 return;
898 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000899
Felix Meschberger2941ef92007-08-20 13:15:16 +0000900 // this will be set below to be given to the service
901 Dictionary dictionary;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000902
Felix Meschberger2941ef92007-08-20 13:15:16 +0000903 // check configuration and call plugins if existing and not new
904 if ( cfg != null && !cfg.isNew() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000905 {
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000906
Felix Meschbergerf4631322008-03-10 12:32:35 +0000907 if ( cfg.isDelivered() )
908 {
909 log( LogService.LOG_DEBUG, "Configuration " + pid + " has already been delivered", null );
910 return;
911 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000912
Felix Meschberger41243192009-01-14 19:59:58 +0000913 Bundle serviceBundle = sr.getBundle();
914 if ( serviceBundle == null )
915 {
916 log( LogService.LOG_INFO, "ServiceFactory for PID " + pid
917 + " seems to already have been unregistered, not updating with configuration", null );
918 return;
919 }
920
Felix Meschberger2941ef92007-08-20 13:15:16 +0000921 // 104.3 Ignore duplicate PIDs from other bundles and report
922 // them to the log
923 // 104.4.1 No update call back for PID already bound to another
924 // bundle location
925 // 104.4.1 assign configuration to bundle if unassigned
Felix Meschberger41243192009-01-14 19:59:58 +0000926 String bundleLocation = serviceBundle.getLocation();
Felix Meschberger2941ef92007-08-20 13:15:16 +0000927 if ( cfg.getBundleLocation() == null )
928 {
929 cfg.setBundleLocation( bundleLocation );
930 }
931 else if ( !bundleLocation.equals( cfg.getBundleLocation() ) )
932 {
933 log( LogService.LOG_ERROR, "Cannot use configuration for " + pid + " requested by bundle "
Felix Meschberger41243192009-01-14 19:59:58 +0000934 + serviceBundle.getLocation() + " but belongs to " + cfg.getBundleLocation(), null );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000935 return;
936 }
937
938 // 104.3 Report an error in the log if more than one service
939 // with
940 // the same PID asks for the configuration
941 if ( cfg.getServiceReference() != null && !sr.equals( cfg.getServiceReference() ) )
942 {
943 log( LogService.LOG_ERROR, "Configuration for " + pid + " has already been used for service "
944 + cfg.getServiceReference() + " and will now also be given to " + sr, null );
945 }
946 else
947 {
948 // assign the configuration to the service
949 cfg.setServiceReference( sr );
950 }
951
952 // prepare the configuration for the service (call plugins)
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000953 dictionary = callPlugins( pid, sr, cfg );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000954 }
955 else
956 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000957 // 104.5.3 ManagedService.updated must be called with null
958 // if no configuration is available
959 dictionary = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000960 }
961
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000962 // update the service with the configuration
963 try
964 {
965 service.updated( dictionary );
Felix Meschbergerf4631322008-03-10 12:32:35 +0000966
967 // if there is nothing to set, don't
968 if ( cfg != null )
969 {
970 cfg.setDelivered( true );
971 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000972 }
973 catch ( ConfigurationException ce )
974 {
975 if ( ce.getProperty() != null )
976 {
977 log( LogService.LOG_ERROR, sr + ": Updating configuration property " + ce.getProperty()
978 + " caused a problem: " + ce.getReason(), ce );
979 }
980 else
981 {
982 log( LogService.LOG_ERROR, sr + ": Updating configuration caused a problem: " + ce.getReason(), ce );
983
984 }
985 }
986 catch ( Throwable t )
987 {
988 log( LogService.LOG_ERROR, sr + ": Unexpected problem updating configuration", t );
989 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000990 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000991
Felix Meschberger432e3872008-03-07 14:58:57 +0000992 public String toString()
993 {
994 return "ManagedService Update: pid=" + pid;
995 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000996 }
997
998 private class ManagedServiceFactoryUpdate implements Runnable
999 {
1000 private String factoryPid;
1001
1002 private ServiceReference sr;
1003
1004 private ManagedServiceFactory service;
1005
1006
1007 ManagedServiceFactoryUpdate( String factoryPid, ServiceReference sr, ManagedServiceFactory service )
1008 {
1009 this.factoryPid = factoryPid;
1010 this.sr = sr;
1011 this.service = service;
1012 }
1013
1014
1015 public void run()
1016 {
1017 Factory factory;
1018 try
1019 {
1020 factory = getFactory( factoryPid );
1021 }
1022 catch ( IOException ioe )
1023 {
1024 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID " + factoryPid, ioe );
1025 return;
1026 }
1027
Felix Meschberger41243192009-01-14 19:59:58 +00001028 Bundle serviceBundle = sr.getBundle();
1029 if ( serviceBundle == null )
1030 {
1031 log( LogService.LOG_INFO, "ManagedServiceFactory for factory PID " + factoryPid
1032 + " seems to already have been unregistered, not updating with factory", null );
1033 return;
1034 }
1035
1036 String bundleLocation = serviceBundle.getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001037 if ( factory.getBundleLocation() == null )
1038 {
1039 // bind to the location of the service if unbound
1040 factory.setBundleLocation( bundleLocation );
1041 }
1042 else if ( !bundleLocation.equals( factory.getBundleLocation() ) )
1043 {
1044 // factory PID is bound to another bundle
1045 log( LogService.LOG_ERROR, "Cannot use Factory configuration for " + factoryPid
Felix Meschberger41243192009-01-14 19:59:58 +00001046 + " requested by bundle " + serviceBundle.getLocation() + " but belongs to "
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001047 + factory.getBundleLocation(), null );
1048 return;
1049 }
1050
1051 Set pids = factory.getPIDs();
1052
1053 for ( Iterator pi = pids.iterator(); pi.hasNext(); )
1054 {
1055 String pid = ( String ) pi.next();
1056 ConfigurationImpl cfg;
1057 try
1058 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001059 cfg = getExistingConfiguration( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001060 }
1061 catch ( IOException ioe )
1062 {
1063 log( LogService.LOG_ERROR, "Error loading configuration for " + pid, ioe );
1064 continue;
1065 }
1066
1067 // sanity check on the configuration
1068 if ( cfg == null )
1069 {
1070 log( LogService.LOG_ERROR, "Configuration " + pid + " referred to by factory " + factoryPid
1071 + " does not exist", null );
1072 factory.removePID( pid );
1073 factory.storeSilently();
1074 continue;
1075 }
Felix Meschberger2941ef92007-08-20 13:15:16 +00001076 else if ( cfg.isNew() )
1077 {
1078 // Configuration has just been created but not yet updated
1079 // we currently just ignore it and have the update mechanism
1080 // provide the configuration to the ManagedServiceFactory
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +00001081 // As of FELIX-612 (not storing new factory configurations)
1082 // this should not happen. We keep this for added stability
1083 // but raise the logging level to error.
1084 log( LogService.LOG_ERROR, "Ignoring new configuration pid=" + pid, null );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001085 continue;
1086 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001087 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1088 {
1089 log( LogService.LOG_ERROR, "Configuration " + pid + " referred to by factory " + factoryPid
Felix Meschbergerbb048982007-08-06 08:56:50 +00001090 + " seems to belong to factory " + cfg.getFactoryPid(), null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001091 factory.removePID( pid );
1092 factory.storeSilently();
1093 continue;
1094 }
1095
Felix Meschbergerf4631322008-03-10 12:32:35 +00001096 // do not re-updated unmodified configuration
1097 if ( cfg.isDelivered() )
1098 {
1099 log( LogService.LOG_DEBUG, "Configuration " + pid + " has already been updated", null );
1100 continue;
1101 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001102
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001103 // check bundle location of configuration
1104 if ( cfg.getBundleLocation() == null )
1105 {
1106 // bind to the location of the service if unbound
1107 cfg.setBundleLocation( bundleLocation );
1108 }
1109 else if ( !bundleLocation.equals( cfg.getBundleLocation() ) )
1110 {
1111 // configuration is bound to another bundle
1112 log( LogService.LOG_ERROR, "Configuration " + pid + " (factory " + factoryPid
1113 + ") belongs to bundle " + cfg.getBundleLocation() + " but was requested for bundle "
1114 + bundleLocation, null );
1115 continue;
1116 }
1117
1118 // prepare the configuration for the service (call plugins)
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001119 // call the plugins with cm.target set to the service's factory PID
1120 // (clarification in Section 104.9.1 of Compendium 4.2)
1121 Dictionary dictionary = callPlugins( factoryPid, sr, cfg );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001122
1123 // update the service with the configuration
1124 try
1125 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001126 // only, if there is non-null configuration data
1127 if ( dictionary != null )
1128 {
Felix Meschberger432e3872008-03-07 14:58:57 +00001129 log( LogService.LOG_DEBUG, sr + ": Updating configuration pid=" + pid, null );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001130 service.updated( pid, dictionary );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001131 cfg.setDelivered( true );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001132 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001133 }
1134 catch ( ConfigurationException ce )
1135 {
1136 if ( ce.getProperty() != null )
1137 {
1138 log( LogService.LOG_ERROR, sr + ": Updating configuration property " + ce.getProperty()
1139 + " caused a problem: " + ce.getReason(), ce );
1140 }
1141 else
1142 {
1143 log( LogService.LOG_ERROR, sr + ": Updating configuration caused a problem: " + ce.getReason(),
1144 ce );
1145
1146 }
1147 }
1148 catch ( Throwable t )
1149 {
1150 log( LogService.LOG_ERROR, sr + ": Unexpected problem updating configuration", t );
1151 }
1152 }
1153 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001154
1155
Felix Meschberger432e3872008-03-07 14:58:57 +00001156 public String toString()
1157 {
1158 return "ManagedServiceFactory Update: factoryPid=" + factoryPid;
1159 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001160 }
1161
1162 private class UpdateConfiguration implements Runnable
1163 {
1164
1165 private ConfigurationImpl config;
1166
1167
1168 UpdateConfiguration( ConfigurationImpl config )
1169 {
1170 this.config = config;
1171 }
1172
1173
1174 public void run()
1175 {
Felix Meschbergerf4631322008-03-10 12:32:35 +00001176 if ( config.isDelivered() )
1177 {
1178 log( LogService.LOG_DEBUG, "Configuration " + config.getPid() + " has already been updated", null );
1179 return;
1180 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001181
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001182 try
1183 {
1184 if ( config.getFactoryPid() == null )
1185 {
1186 ServiceReference[] sr = bundleContext.getServiceReferences( ManagedService.class.getName(), "("
1187 + Constants.SERVICE_PID + "=" + config.getPid() + ")" );
1188 if ( sr != null && sr.length > 0 )
1189 {
1190 ManagedService srv = ( ManagedService ) bundleContext.getService( sr[0] );
1191 try
1192 {
1193 // bind the configuration, fail if bound to another
1194 // bundle !!
1195 // check bundle location of configuration
1196 String bundleLocation = sr[0].getBundle().getLocation();
1197 if ( config.getBundleLocation() == null )
1198 {
1199 // bind to the location of the service if
1200 // unbound
1201 config.setBundleLocation( bundleLocation );
1202 }
1203 else if ( !bundleLocation.equals( config.getBundleLocation() ) )
1204 {
1205 // configuration is bound to another bundle
1206 log( LogService.LOG_ERROR, "Configuration " + config.getPid() + " belongs to bundle "
1207 + config.getBundleLocation() + " but was requested for bundle " + bundleLocation,
1208 null );
1209 return;
1210 }
1211
Felix Meschbergerbb048982007-08-06 08:56:50 +00001212 // prepare the configuration for the service (call plugins)
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001213 Dictionary dictionary = callPlugins( config.getPid(), sr[0], config );
Felix Meschbergerbb048982007-08-06 08:56:50 +00001214
1215 // update the ManagedService with the properties
1216 srv.updated( dictionary );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001217 config.setDelivered( true );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001218 }
1219 finally
1220 {
1221 bundleContext.ungetService( sr[0] );
1222 }
1223 }
1224 }
1225 else
1226 {
1227 ServiceReference[] sr = bundleContext.getServiceReferences( ManagedServiceFactory.class.getName(),
1228 "(" + Constants.SERVICE_PID + "=" + config.getFactoryPid() + ")" );
1229 if ( sr != null && sr.length > 0 )
1230 {
1231 ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext.getService( sr[0] );
1232 try
1233 {
1234 // bind the configuration, fail if bound to another
1235 // bundle !!
1236 // check bundle location of configuration
1237 String bundleLocation = sr[0].getBundle().getLocation();
1238 if ( config.getBundleLocation() == null )
1239 {
1240 // bind to the location of the service if
1241 // unbound
1242 config.setBundleLocation( bundleLocation );
1243 }
1244 else if ( !bundleLocation.equals( config.getBundleLocation() ) )
1245 {
1246 // configuration is bound to another bundle
1247 log( LogService.LOG_ERROR, "Configuration " + config.getPid() + " (factory "
1248 + config.getFactoryPid() + ") belongs to bundle " + config.getBundleLocation()
1249 + " but was requested for bundle " + bundleLocation, null );
1250 return;
1251 }
1252
Felix Meschbergerbb048982007-08-06 08:56:50 +00001253 // prepare the configuration for the service (call plugins)
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001254 // call the plugins with cm.target set to the service's factory PID
1255 // (clarification in Section 104.9.1 of Compendium 4.2)
1256 Dictionary dictionary = callPlugins( config.getFactoryPid(), sr[0], config );
Felix Meschbergerbb048982007-08-06 08:56:50 +00001257
1258 // update the ManagedServiceFactory with the properties
Felix Meschberger2941ef92007-08-20 13:15:16 +00001259 // only, if there is non-null configuration data
1260 if ( dictionary != null )
1261 {
1262 srv.updated( config.getPid(), dictionary );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001263 config.setDelivered( true );
Felix Meschberger2941ef92007-08-20 13:15:16 +00001264 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001265 }
1266 finally
1267 {
1268 bundleContext.ungetService( sr[0] );
1269 }
1270 }
1271 }
1272 }
1273 catch ( ConfigurationException ce )
1274 {
1275 if ( ce.getProperty() != null )
1276 {
1277 log( LogService.LOG_ERROR, "Updating configuration property " + ce.getProperty()
1278 + " caused a problem: " + ce.getReason(), ce );
1279 }
1280 else
1281 {
1282 log( LogService.LOG_ERROR, "Updating configuration caused a problem: " + ce.getReason(), ce );
1283
1284 }
1285 }
1286 catch ( Throwable t )
1287 {
1288 log( LogService.LOG_ERROR, "Unexpected problem updating configuration", t );
1289 }
1290
Felix Meschberger66423332007-08-22 08:46:34 +00001291 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPid(), config.getFactoryPid() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001292 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001293
Felix Meschberger432e3872008-03-07 14:58:57 +00001294 public String toString()
1295 {
1296 return "Update: pid=" + config.getPid();
1297 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001298 }
1299
1300 private class DeleteConfiguration implements Runnable
1301 {
Felix Meschberger66423332007-08-22 08:46:34 +00001302
Felix Meschbergerf4631322008-03-10 12:32:35 +00001303 private ConfigurationImpl config;
Felix Meschberger66423332007-08-22 08:46:34 +00001304 private String pid;
1305 private String factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001306
1307
1308 DeleteConfiguration( ConfigurationImpl config )
1309 {
Felix Meschbergerf4631322008-03-10 12:32:35 +00001310 this.config = config;
Felix Meschberger66423332007-08-22 08:46:34 +00001311 this.pid = config.getPid();
1312 this.factoryPid = config.getFactoryPid();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001313 }
1314
1315
1316 public void run()
1317 {
Felix Meschbergerf4631322008-03-10 12:32:35 +00001318 if ( config.isDelivered() )
1319 {
1320 log( LogService.LOG_DEBUG, "Deletion of configuration " + pid + " has already been delivered", null );
1321 return;
1322 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001323
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001324 try
1325 {
Felix Meschberger66423332007-08-22 08:46:34 +00001326 if ( factoryPid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001327 {
1328 ServiceReference[] sr = bundleContext.getServiceReferences( ManagedService.class.getName(), "("
Felix Meschberger66423332007-08-22 08:46:34 +00001329 + Constants.SERVICE_PID + "=" + pid + ")" );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001330 if ( sr != null && sr.length > 0 )
1331 {
1332 ManagedService srv = ( ManagedService ) bundleContext.getService( sr[0] );
1333 try
1334 {
1335 srv.updated( null );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001336 config.setDelivered( true );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001337 }
1338 finally
1339 {
1340 bundleContext.ungetService( sr[0] );
1341 }
1342 }
1343 }
1344 else
1345 {
1346 // remove the pid from the factory
Felix Meschberger66423332007-08-22 08:46:34 +00001347 Factory factory = getFactory( factoryPid );
1348 factory.removePID( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001349 factory.store();
1350
1351 ServiceReference[] sr = bundleContext.getServiceReferences( ManagedServiceFactory.class.getName(),
Felix Meschberger66423332007-08-22 08:46:34 +00001352 "(" + Constants.SERVICE_PID + "=" + factoryPid + ")" );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001353 if ( sr != null && sr.length > 0 )
1354 {
1355 ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext.getService( sr[0] );
1356 try
1357 {
Felix Meschberger66423332007-08-22 08:46:34 +00001358 srv.deleted( pid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001359 config.setDelivered( true );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001360 }
1361 finally
1362 {
1363 bundleContext.ungetService( sr[0] );
1364 }
1365 }
1366 }
1367 }
1368 catch ( ConfigurationException ce )
1369 {
1370 if ( ce.getProperty() != null )
1371 {
1372 log( LogService.LOG_ERROR, "Updating configuration property " + ce.getProperty()
1373 + " caused a problem: " + ce.getReason(), ce );
1374 }
1375 else
1376 {
1377 log( LogService.LOG_ERROR, "Updating configuration caused a problem: " + ce.getReason(), ce );
1378
1379 }
1380 }
1381 catch ( Throwable t )
1382 {
1383 log( LogService.LOG_ERROR, "Unexpected problem updating configuration", t );
1384 }
1385
Felix Meschberger66423332007-08-22 08:46:34 +00001386 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, pid, factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001387 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001388
Felix Meschberger432e3872008-03-07 14:58:57 +00001389 public String toString()
1390 {
1391 return "Delete: pid=" + pid;
1392 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001393 }
1394
1395 private class FireConfigurationEvent implements Runnable
1396 {
1397 private int type;
1398
Felix Meschberger66423332007-08-22 08:46:34 +00001399 private String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001400
Felix Meschberger66423332007-08-22 08:46:34 +00001401 private String factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001402
1403
Felix Meschberger66423332007-08-22 08:46:34 +00001404 FireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001405 {
1406 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001407 this.pid = pid;
1408 this.factoryPid = factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001409 }
1410
1411
1412 public void run()
1413 {
1414 // get the listeners
1415 ServiceReference[] srs = configurationListenerTracker.getServiceReferences();
1416 if ( srs == null || srs.length == 0 )
1417 {
1418 return;
1419 }
1420
Felix Meschbergerb4f83e42009-01-15 08:53:36 +00001421 ConfigurationEvent event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001422
1423 for ( int i = 0; i < srs.length; i++ )
1424 {
1425 ConfigurationListener cl = ( ConfigurationListener ) configurationListenerTracker.getService( srs[i] );
1426 try
1427 {
1428 cl.configurationEvent( event );
1429 }
1430 catch ( Throwable t )
1431 {
1432 log( LogService.LOG_ERROR, "Unexpected problem delivery configuration event to " + srs[i], t );
1433 }
1434 }
1435 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001436
Felix Meschberger432e3872008-03-07 14:58:57 +00001437 public String toString()
1438 {
1439 return "Fire ConfigurationEvent: pid=" + pid;
1440 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001441 }
1442
Carsten Ziegeler41683982007-12-27 08:35:27 +00001443 private static abstract class AbstractManagedServiceTracker extends ServiceTracker
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001444 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001445 protected final ConfigurationManager cm;
1446
1447 AbstractManagedServiceTracker( ConfigurationManager cm, String className )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001448 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001449 super( cm.bundleContext, className, null );
1450 this.cm = cm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001451 open();
1452 }
1453
1454
1455 public void removedService( ServiceReference reference, Object service )
1456 {
1457 // check whether we can take back the configuration object
1458 String pid = ( String ) reference.getProperty( Constants.SERVICE_PID );
1459 if ( pid != null )
1460 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001461 ConfigurationImpl cfg = cm.getCachedConfiguration( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001462 if ( cfg != null && reference.equals( cfg.getServiceReference() ) )
1463 {
1464 cfg.setServiceReference( null );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001465 cfg.setDelivered( false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001466 }
1467 }
1468
1469 super.removedService( reference, service );
1470 }
1471 }
1472
Carsten Ziegeler41683982007-12-27 08:35:27 +00001473 private static class ManagedServiceTracker extends AbstractManagedServiceTracker
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001474 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001475
1476 ManagedServiceTracker(ConfigurationManager cm)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001477 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001478 super( cm, ManagedService.class.getName() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001479 }
1480
1481
1482 public Object addingService( ServiceReference reference )
1483 {
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001484 Object serviceObject = super.addingService( reference );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001485
1486 // configure the managed service
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001487 if ( serviceObject instanceof ManagedService )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001488 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001489 cm.configure(reference, ( ManagedService ) serviceObject);
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001490 }
1491 else
1492 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001493 cm.log( LogService.LOG_WARNING, "Service " + serviceObject + " is not a ManagedService", null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001494 }
1495
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001496 return serviceObject;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001497 }
1498 }
1499
Carsten Ziegeler41683982007-12-27 08:35:27 +00001500 private static class ManagedServiceFactoryTracker extends AbstractManagedServiceTracker
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001501 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001502 ManagedServiceFactoryTracker(ConfigurationManager cm)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001503 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001504 super( cm, ManagedServiceFactory.class.getName() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001505 }
1506
1507
1508 public Object addingService( ServiceReference reference )
1509 {
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001510 Object serviceObject = super.addingService( reference );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001511
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001512 // configure the managed service factory
1513 if ( serviceObject instanceof ManagedServiceFactory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001514 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001515 cm.configure( reference, ( ManagedServiceFactory ) serviceObject );
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001516 }
1517 else
1518 {
Carsten Ziegeler41683982007-12-27 08:35:27 +00001519 cm.log( LogService.LOG_WARNING, "Service " + serviceObject + " is not a ManagedServiceFactory", null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001520 }
1521
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001522 return serviceObject;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001523 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001524
Felix Meschbergerf4631322008-03-10 12:32:35 +00001525 public void removedService( ServiceReference reference, Object service )
1526 {
1527 // check whether we can take back the configuration objects
1528 String factoryPid = ( String ) reference.getProperty( Constants.SERVICE_PID );
1529 if ( factoryPid != null )
1530 {
1531 Factory factory = cm.getCachedFactory( factoryPid );
1532 if ( factory != null )
1533 {
1534 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
1535 {
1536 String pid = ( String ) pi.next();
1537 ConfigurationImpl cfg = cm.getCachedConfiguration( pid );
1538 if ( cfg != null )
1539 {
1540 cfg.setDelivered( false );
1541 }
1542 }
1543 }
1544 }
1545
1546 super.removedService( reference, service );
1547 }
1548
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001549 }
1550}