blob: 5a92dd2ea0c04c27d3d360e4ac75e9729f85b2b8 [file] [log] [blame]
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001/*
2 * 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;
24import java.util.ArrayList;
25import java.util.Comparator;
26import java.util.Dictionary;
27import java.util.Enumeration;
28import java.util.HashMap;
29import java.util.Hashtable;
30import java.util.Iterator;
31import java.util.List;
32import java.util.Map;
33import java.util.Set;
34import java.util.SortedSet;
35import java.util.TreeSet;
36
37import org.apache.felix.cm.PersistenceManager;
38import org.apache.felix.cm.file.FilePersistenceManager;
39import org.osgi.framework.BundleActivator;
40import org.osgi.framework.BundleContext;
41import org.osgi.framework.BundleEvent;
42import org.osgi.framework.BundleListener;
43import org.osgi.framework.Constants;
44import org.osgi.framework.Filter;
45import org.osgi.framework.InvalidSyntaxException;
46import org.osgi.framework.ServiceReference;
47import org.osgi.service.cm.ConfigurationAdmin;
48import org.osgi.service.cm.ConfigurationEvent;
49import org.osgi.service.cm.ConfigurationException;
50import org.osgi.service.cm.ConfigurationListener;
51import org.osgi.service.cm.ConfigurationPlugin;
52import org.osgi.service.cm.ManagedService;
53import org.osgi.service.cm.ManagedServiceFactory;
54import org.osgi.service.log.LogService;
55import org.osgi.util.tracker.ServiceTracker;
56
57
58/**
59 * The <code>ConfigurationManager</code> is the central class in this
60 * implementation of the Configuration Admin Service Specification. As such it
61 * has the following tasks:
62 * <ul>
63 * <li>It is a <code>BundleActivator</code> which is called when the bundle
64 * is started and stopped.
65 * <li>It is a <code>BundleListener</code> which gets informed when the
66 * states of bundles change. Mostly this is needed to unbind any bound
67 * configuration in case a bundle is uninstalled.
68 * <li>It is a <code>ServiceListener</code> which gets informed when
69 * <code>ManagedService</code> and <code>ManagedServiceFactory</code>
70 * services are registered and unregistered. This is used to provide
71 * configuration to these services. As a service listener it also listens for
72 * {@link PersistenceManager} instances being registered to support different
73 * configuration persistence layers.
74 * <li>A {@link ConfigurationAdminFactory} instance is registered as the
75 * <code>ConfigurationAdmin</code> service.
76 * <li>A {@link FilePersistenceManager} instance is registered as a default
77 * {@link PersistenceManager}.
78 * <li>Last but not least this instance manages all tasks laid out in the
79 * specification such as maintaining configuration, taking care of configuration
80 * events, etc.
81 * </ul>
82 * <p>
83 * The default {@link FilePersistenceManager} is configured with a configuration
84 * location taken from the <code>felix.cm.dir</code> framework property. If
85 * this property is not set the <code>config</code> directory in the current
86 * working directory as specified in the <code>user.dir</code> system property
87 * is used.
88 *
89 * @author fmeschbe
90 */
91public class ConfigurationManager implements BundleActivator, BundleListener
92{
93
94 /**
95 * The name of the bundle context property defining the location for the
96 * configuration files (value is "felix.cm.dir").
97 *
98 * @see #FilePersistenceManager(BundleContext)
99 */
100 public static final String CM_CONFIG_DIR = "felix.cm.dir";
101
102 // random number generator to create configuration PIDs for factory
103 // configurations
104 private static SecureRandom numberGenerator;
105
106 // comparator used to keep the ordered persistence manager map
107 private static final Comparator cmRankComp = new RankingComparator( true, ConfigurationPlugin.CM_RANKING );
108
109 // the BundleContext of the Configuration Admin Service bundle
110 private BundleContext bundleContext;
111
112 // the service reference to the ConfigurationAdmin service
113 private ServiceReference configurationAdminReference;
114
115 // the ServiceTracker to emit log services (see log(int, String, Throwable))
116 private ServiceTracker logTracker;
117
118 // the ConfigurationEvent listeners
119 private ServiceTracker configurationListenerTracker;
120
121 // service tracker for managed services
122 private ServiceTracker managedServiceTracker;
123
124 // service tracker for managed service factories
125 private ServiceTracker managedServiceFactoryTracker;
126
127 // PersistenceManager services
128 private ServiceTracker persistenceManagerTracker;
129
130 // the thread used to schedule tasks required to run asynchronously
131 private UpdateThread updateThread;
132
133 /**
134 * The actual list of {@link PersistenceManager persistence managers} to use
135 * when looking for configuration data. This list is built from the
136 * {@link #persistenceManagerMap}, which is ordered according to the
137 * {@link RankingComparator}.
138 */
139 private PersistenceManager[] persistenceManagers;
140
141 // the persistenceManagerTracker.getTrackingCount when the
142 // persistenceManagers were last got
143 private int pmtCount;
144
145 // the cache of Factory instances mapped by their factory PID
146 private Map factories;
147
148 // the cache of Configuration instances mapped by their PID
149 private Map configurations;
150
151
152 public void start( BundleContext bundleContext )
153 {
154 // track the log service using a ServiceTracker
155 logTracker = new ServiceTracker( bundleContext, LogService.class.getName(), null );
156 logTracker.open();
157
158 // set up some fields
159 this.bundleContext = bundleContext;
160 this.factories = new HashMap();
161 this.configurations = new HashMap();
162
163 // configurationlistener support
164 configurationListenerTracker = new ServiceTracker( bundleContext, ConfigurationListener.class.getName(), null );
165 configurationListenerTracker.open();
166
167 // initialize the asynchonous updater thread
168 this.updateThread = new UpdateThread( this );
169 this.updateThread.start();
170
171 // set up the location (might throw IllegalArgumentException)
172 try
173 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000174 FilePersistenceManager fpm = new FilePersistenceManager( bundleContext, bundleContext
175 .getProperty( CM_CONFIG_DIR ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000176 Hashtable props = new Hashtable();
177 props.put( Constants.SERVICE_PID, fpm.getClass().getName() );
178 props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
179 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
180 props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
181 bundleContext.registerService( PersistenceManager.class.getName(), fpm, props );
182 }
183 catch ( IllegalArgumentException iae )
184 {
185 log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
186 }
187
188 // register as bundle and service listener
189 bundleContext.addBundleListener( this );
190
191 // get all persistence managers to begin with
192 pmtCount = 1; // make sure to get the persistence managers at least
193 // once
194 persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
195 persistenceManagerTracker.open();
196
197 // create and register configuration admin - start after PM tracker ...
198 ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
199 Hashtable props = new Hashtable();
200 props.put( Constants.SERVICE_PID, "org.apache.felix.cm.ConfigurationAdmin" );
201 props.put( Constants.SERVICE_DESCRIPTION, "Configuration Admin Service Specification 1.2 Implementation" );
202 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
203 bundleContext.registerService( ConfigurationAdmin.class.getName(), caf, props );
204
205 // start handling ManagedService[Factory] services
206 managedServiceTracker = new ManagedServiceTracker();
207 managedServiceFactoryTracker = new ManagedServiceFactoryTracker();
208 }
209
210
211 public void stop( BundleContext bundleContext )
212 {
213 // stop handling ManagedService[Factory] services
214 managedServiceFactoryTracker.close();
215 managedServiceTracker.close();
216
217 // don't care for PersistenceManagers any more
218 persistenceManagerTracker.close();
219
220 // stop listening for events
221 bundleContext.removeBundleListener( this );
222
223 if ( configurationListenerTracker != null )
224 {
225 configurationListenerTracker.close();
226 }
227
228 if ( updateThread != null )
229 {
230 // terminate asynchrounous updates
231 updateThread.terminate();
232
233 // wait for all updates to terminate
234 try
235 {
236 updateThread.join();
237 }
238 catch ( InterruptedException ie )
239 {
240 // don't really care
241 }
242 }
243
244 if ( logTracker != null )
245 {
246 logTracker.close();
247 }
248
249 this.bundleContext = null;
250 this.configurations = null;
251 }
252
253
254 // ---------- Configuration caching support --------------------------------
255
256 ConfigurationImpl getCachedConfiguration( String pid )
257 {
258 synchronized ( configurations )
259 {
260 return ( ConfigurationImpl ) configurations.get( pid );
261 }
262 }
263
264
265 Iterator getCachedConfigurations()
266 {
267 synchronized ( configurations )
268 {
269 return configurations.values().iterator();
270 }
271 }
272
273
Felix Meschberger2941ef92007-08-20 13:15:16 +0000274 ConfigurationImpl cacheConfiguration( ConfigurationImpl configuration )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000275 {
276 synchronized ( configurations )
277 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000278 Object existing = configurations.get( configuration.getPid() );
279 if ( existing != null )
280 {
281 return ( ConfigurationImpl ) existing;
282 }
283
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000284 configurations.put( configuration.getPid(), configuration );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000285 return configuration;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000286 }
287 }
288
289
290 void removeConfiguration( ConfigurationImpl configuration )
291 {
292 synchronized ( configurations )
293 {
294 configurations.remove( configuration.getPid() );
295 }
296 }
297
298
299 // ---------- ConfigurationAdminImpl support -------------------------------
300
301 /*
302 * (non-Javadoc)
303 *
304 * @see org.osgi.service.cm.ConfigurationAdmin#createFactoryConfiguration(java.lang.String)
305 */
306 ConfigurationImpl createFactoryConfiguration( ConfigurationAdminImpl configurationAdmin, String factoryPid )
307 throws IOException
308 {
309 Factory factory = getFactory( factoryPid );
310
311 // check Persmission if factory is bound to another bundle
312 if ( factory.getBundleLocation() != null
313 && !factory.getBundleLocation().equals( configurationAdmin.getBundle().getLocation() ) )
314 {
315 configurationAdmin.checkPermission();
316 }
317
318 // create the configuration
319 String pid = createPid( factoryPid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000320 ConfigurationImpl config = createConfiguration( pid, factoryPid, configurationAdmin.getBundle().getLocation() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000321
322 // add the configuration to the factory
323 factory.addPID( pid );
324 factory.store();
325
326 return config;
327 }
328
329
330 /*
331 * (non-Javadoc)
332 *
333 * @see org.osgi.service.cm.ConfigurationAdmin#createFactoryConfiguration(java.lang.String,
334 * java.lang.String)
335 */
336 ConfigurationImpl createFactoryConfiguration( String factoryPid, String location ) throws IOException
337 {
338 // create the configuration
339 String pid = createPid( factoryPid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000340 ConfigurationImpl config = createConfiguration( pid, factoryPid, location );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000341
342 // add the configuration to the factory
343 Factory factory = getFactory( factoryPid );
344 factory.addPID( pid );
345 factory.store();
346
347 return config;
348 }
349
350
Felix Meschberger2941ef92007-08-20 13:15:16 +0000351 ConfigurationImpl getExistingConfiguration( String pid ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000352 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000353 ConfigurationImpl config = getCachedConfiguration( pid );
354 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000355 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000356 return config;
357 }
358
359 PersistenceManager[] pmList = getPersistenceManagers();
360 for ( int i = 0; i < pmList.length; i++ )
361 {
362 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000363 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000364 Dictionary props = pmList[i].load( pid );
365 config = new ConfigurationImpl( this, pmList[i], props );
366 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000367 }
368 }
Felix Meschberger2941ef92007-08-20 13:15:16 +0000369
370 // neither the cache nor any persistence manager has configuration
371 return null;
372 }
373
374
375 ConfigurationImpl getConfiguration( String pid, String bundleLocation ) throws IOException
376 {
377 // check for existing (cached or persistent) configuration
378 ConfigurationImpl config = getExistingConfiguration( pid );
379 if ( config != null )
380 {
381 return config;
382 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000383
Felix Meschberger2941ef92007-08-20 13:15:16 +0000384 // else create new configuration also setting the bundle location
385 return createConfiguration( pid, null, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000386 }
387
388
389 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
390 throws IOException, InvalidSyntaxException
391 {
392 Filter filter = null;
393 if ( filterString != null )
394 {
395 filter = bundleContext.createFilter( filterString );
396 }
397
398 boolean unprivileged = configurationAdmin != null && !configurationAdmin.hasPermission();
399 String location = unprivileged ? configurationAdmin.getBundle().getLocation() : null;
400
401 List configList = new ArrayList();
402
403 PersistenceManager[] pmList = getPersistenceManagers();
404 for ( int i = 0; i < pmList.length; i++ )
405 {
406 Enumeration configs = pmList[i].getDictionaries();
407 while ( configs.hasMoreElements() )
408 {
409 Dictionary config = ( Dictionary ) configs.nextElement();
410
411 // ignore non-Configuration dictionaries
Felix Meschberger86a0d172007-07-04 07:15:01 +0000412 String pid = ( String ) config.get( Constants.SERVICE_PID );
413 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000414 {
415 continue;
416 }
417
418 // ignore this config if not privileged and not bound to bundle
419 if ( unprivileged )
420 {
421 Object boundLocation = config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION );
422 if ( !location.equals( boundLocation ) )
423 {
424 continue;
425 }
426 }
427
428 // check filter
429 if ( filter == null || filter.match( config ) )
430 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000431 // ensure the service.pid and returned a cached config if available
432 ConfigurationImpl cfg = getCachedConfiguration( pid );
433 if ( cfg == null )
434 {
435 cfg = new ConfigurationImpl( this, pmList[i], config );
436 }
437
438 configList.add( cfg );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000439 }
440 }
441 }
442
Felix Meschberger8faceff2007-07-04 07:19:48 +0000443 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000444 .size()] );
445 }
446
447
448 void deleted( ConfigurationImpl config )
449 {
450 // remove the configuration from the cache
451 removeConfiguration( config );
452 updateThread.schedule( new DeleteConfiguration( config ) );
453 }
454
455
456 void updated( ConfigurationImpl config )
457 {
458 updateThread.schedule( new UpdateConfiguration( config ) );
459 }
460
461
Felix Meschberger66423332007-08-22 08:46:34 +0000462 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000463 {
464
Felix Meschberger66423332007-08-22 08:46:34 +0000465 updateThread.schedule( new FireConfigurationEvent( type, pid, factoryPid) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000466 }
467
468
469 // ---------- BundleListener -----------------------------------------------
470
471 public void bundleChanged( BundleEvent event )
472 {
473 if ( event.getType() == BundleEvent.UNINSTALLED )
474 {
475 String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000476
477 try
478 {
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000479 PersistenceManager[] pmList = getPersistenceManagers();
480 for ( int i = 0; i < pmList.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000481 {
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000482 Enumeration configs = pmList[i].getDictionaries();
483 while ( configs.hasMoreElements() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000484 {
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000485 Dictionary config = ( Dictionary ) configs.nextElement();
486
487 String pid = ( String ) config.get( Constants.SERVICE_PID );
488 if ( pid != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000489 {
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000490 ConfigurationImpl cfg = getCachedConfiguration( pid );
491 if ( cfg == null )
492 {
493 cfg = new ConfigurationImpl( this, pmList[i], config );
494 }
495
496 if ( location.equals( cfg.getBundleLocation() ) )
497 {
498 cfg.setBundleLocation( null );
499 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000500 }
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000501 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000502 {
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000503
504 Factory factory = Factory.getFactory( pmList[i], config );
505 if ( factory != null )
506 {
507 Factory cachedFactory = ( Factory ) factories.get( factory.getFactoryPid() );
508 if ( cachedFactory != null )
509 {
510 factory = cachedFactory;
511 }
512
513 if ( location.equals( factory.getBundleLocation() ) )
514 {
515 factory.setBundleLocation( null );
516 }
517 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000518 }
519 }
520 }
Felix Meschbergere2ca8332007-06-06 06:27:31 +0000521
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000522 }
523 catch ( Exception e )
524 {
525 log( LogService.LOG_WARNING, "Problem unbinding configurations for bundle " + location, e );
526 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000527 }
528 }
529
530
531 // ---------- internal -----------------------------------------------------
532
533 private PersistenceManager[] getPersistenceManagers()
534 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000535 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
536 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000537 {
538
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000539 PersistenceManager[] pm;
540
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000541 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
542 if ( refs == null || refs.length == 0 )
543 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000544 pm = new PersistenceManager[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000545 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000546 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000547 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000548 // sort the references according to the cmRanking property
549 SortedSet pms = new TreeSet( new RankingComparator( false ) );
550 for ( int i = 0; i < refs.length; i++ )
551 {
552 pms.add( refs[i] );
553 }
554
555 // create the service array from the sorted set of referenecs
556 pm = new PersistenceManager[pms.size()];
557 int pmIndex = 0;
558 for ( Iterator pi = pms.iterator(); pi.hasNext(); pmIndex++)
559 {
560 ServiceReference ref = ( ServiceReference ) pi.next();
561 pm[pmIndex] = ( PersistenceManager ) persistenceManagerTracker.getService( ref );
562 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000563 }
564
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000565 pmtCount = currentPmtCount;
566 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000567 }
568
569 return persistenceManagers;
570 }
571
572
573 private void configure( ServiceReference sr, ManagedService service )
574 {
575 String pid = ( String ) sr.getProperty( Constants.SERVICE_PID );
576 if ( pid != null )
577 {
578 ManagedServiceUpdate update = new ManagedServiceUpdate( pid, sr, service );
579 updateThread.schedule( update );
580 }
581
582 }
583
584
585 private void configure( ServiceReference sr, ManagedServiceFactory service )
586 {
587 String pid = ( String ) sr.getProperty( Constants.SERVICE_PID );
588 if ( pid != null )
589 {
590 ManagedServiceFactoryUpdate update = new ManagedServiceFactoryUpdate( pid, sr, service );
591 updateThread.schedule( update );
592 }
593
594 }
595
596
Felix Meschberger2941ef92007-08-20 13:15:16 +0000597 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000598 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000599 // create the configuration (which will also be stored immediately)
600 ConfigurationImpl config = new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid,
601 bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000602
Felix Meschberger2941ef92007-08-20 13:15:16 +0000603 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000604 }
605
606
607 Factory getFactory( String factoryPid ) throws IOException
608 {
609 Factory factory = ( Factory ) factories.get( factoryPid );
610 if ( factory != null )
611 {
612 return factory;
613 }
614
615 PersistenceManager[] pmList = getPersistenceManagers();
616 for ( int i = 0; i < pmList.length; i++ )
617 {
618 if ( Factory.exists( pmList[i], factoryPid ) )
619 {
620 factory = Factory.load( pmList[i], factoryPid );
621 factories.put( factoryPid, factory );
622 return factory;
623 }
624 }
625
626 // if getting here, there is no configuration yet, optionally create new
627 return createFactory( factoryPid );
628 }
629
630
631 Factory createFactory( String factoryPid )
632 {
633 Factory factory = new Factory( getPersistenceManagers()[0], factoryPid );
634 factories.put( factoryPid, factory );
635 return factory;
636 }
637
638
Felix Meschberger2941ef92007-08-20 13:15:16 +0000639 /**
640 * Calls the registered configuration plugins on the given configuration
641 * object unless the configuration has just been created and not been
642 * updated yet.
643 *
644 * @param sr The service reference of the managed service (factory) which
645 * is to be updated with configuration
646 * @param cfg The configuration object whose properties have to be passed
647 * through the plugins
648 * @return The properties from the configuration object passed through the
649 * plugins or <code>null</code> if the configuration object has
650 * been newly created and no properties exist yet.
651 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000652 private Dictionary callPlugins( ServiceReference sr, ConfigurationImpl cfg )
653 {
654 Dictionary props = cfg.getProperties();
Felix Meschberger2941ef92007-08-20 13:15:16 +0000655
656 // guard against NPE for new configuration never updated
657 if (props == null) {
658 return null;
659 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000660
661 ServiceReference[] plugins = null;
662 try
663 {
664 String pid = ( String ) sr.getProperty( Constants.SERVICE_PID );
665 String filter = "(|(!(cm.target=*))(cm.target=" + pid + "))";
666 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
667
668 }
669 catch ( InvalidSyntaxException ise )
670 {
671 // no filter, no exception ...
672 }
673
674 // abort early if there are no plugins
675 if ( plugins == null || plugins.length == 0 )
676 {
677 return props;
678 }
679
680 // sort the plugins by their service.cmRanking
681 SortedSet pluginSet = new TreeSet( cmRankComp );
682 for ( int i = 0; plugins != null && i < plugins.length; i++ )
683 {
684 pluginSet.add( plugins[i] );
685 }
686
687 // call the plugins in order
688 for ( Iterator pi = pluginSet.iterator(); pi.hasNext(); )
689 {
690 ServiceReference pluginRef = ( ServiceReference ) pi.next();
691 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
692 try
693 {
694 plugin.modifyConfiguration( sr, props );
695 }
696 catch ( Throwable t )
697 {
698 log( LogService.LOG_ERROR, "Unexpected problem calling" + " configuration plugin", t );
699 }
700 finally
701 {
702 // ensure ungetting the plugin
703 bundleContext.ungetService( pluginRef );
704 }
705 cfg.setAutoProperties( props, false );
706 }
707
708 return props;
709 }
710
711
712 /**
713 * Creates a PID for the given factoryPid
714 *
715 * @param factoryPid
716 * @return
717 */
718 private static String createPid( String factoryPid )
719 {
720 SecureRandom ng = numberGenerator;
721 if ( ng == null )
722 {
723 numberGenerator = ng = new SecureRandom();
724 }
725
726 byte[] randomBytes = new byte[16];
727 ng.nextBytes( randomBytes );
728 randomBytes[6] &= 0x0f; /* clear version */
729 randomBytes[6] |= 0x40; /* set to version 4 */
730 randomBytes[8] &= 0x3f; /* clear variant */
731 randomBytes[8] |= 0x80; /* set to IETF variant */
732
733 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
734
735 // prefix the new pid with the factory pid
736 buf.append( factoryPid ).append( "." );
737
738 // serialize the UUID into the buffer
739 for ( int i = 0; i < randomBytes.length; i++ )
740 {
741
742 if ( i == 4 || i == 6 || i == 8 || i == 10 )
743 {
744 buf.append( '-' );
745 }
746
747 int val = randomBytes[i] & 0xff;
748 buf.append( Integer.toHexString( val >> 4 ) );
749 buf.append( Integer.toHexString( val & 0xf ) );
750 }
751
752 return buf.toString();
753 }
754
755
756 void log( int level, String message, Throwable t )
757 {
758 LogService log = ( LogService ) logTracker.getService();
759 if ( log != null )
760 {
761 log.log( configurationAdminReference, level, message, t );
762 return;
763 }
764
765 String code;
766 switch ( level )
767 {
768 case LogService.LOG_INFO:
769 code = "*INFO *";
770 break;
771
772 case LogService.LOG_WARNING:
773 code = "*WARN *";
774 break;
775
776 case LogService.LOG_ERROR:
777 code = "*ERROR*";
778 break;
779
780 case LogService.LOG_DEBUG:
781 default:
782 code = "*DEBUG*";
783 }
784
785 System.err.println( code + " " + message );
786 if ( t != null )
787 {
788 t.printStackTrace( System.err );
789 }
790 }
791
792 // ---------- inner classes ------------------------------------------------
793
794 private class ManagedServiceUpdate implements Runnable
795 {
796 private String pid;
797
798 private ServiceReference sr;
799
800 private ManagedService service;
801
802
803 ManagedServiceUpdate( String pid, ServiceReference sr, ManagedService service )
804 {
805 this.pid = pid;
806 this.sr = sr;
807 this.service = service;
808 }
809
810
811 public void run()
812 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000813 // get or load configuration for the pid
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000814 ConfigurationImpl cfg;
815 try
816 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000817 cfg = getExistingConfiguration( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000818 }
819 catch ( IOException ioe )
820 {
821 log( LogService.LOG_ERROR, "Error loading configuration for " + pid, ioe );
822 return;
823 }
Felix Meschberger2941ef92007-08-20 13:15:16 +0000824
825 // this will be set below to be given to the service
826 Dictionary dictionary;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000827
Felix Meschberger2941ef92007-08-20 13:15:16 +0000828 // check configuration and call plugins if existing and not new
829 if ( cfg != null && !cfg.isNew() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000830 {
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000831
Felix Meschberger2941ef92007-08-20 13:15:16 +0000832 // 104.3 Ignore duplicate PIDs from other bundles and report
833 // them to the log
834 // 104.4.1 No update call back for PID already bound to another
835 // bundle location
836 // 104.4.1 assign configuration to bundle if unassigned
837 String bundleLocation = sr.getBundle().getLocation();
838 if ( cfg.getBundleLocation() == null )
839 {
840 cfg.setBundleLocation( bundleLocation );
841 }
842 else if ( !bundleLocation.equals( cfg.getBundleLocation() ) )
843 {
844 log( LogService.LOG_ERROR, "Cannot use configuration for " + pid + " requested by bundle "
845 + sr.getBundle().getLocation() + " but belongs to " + cfg.getBundleLocation(), null );
846 return;
847 }
848
849 // 104.3 Report an error in the log if more than one service
850 // with
851 // the same PID asks for the configuration
852 if ( cfg.getServiceReference() != null && !sr.equals( cfg.getServiceReference() ) )
853 {
854 log( LogService.LOG_ERROR, "Configuration for " + pid + " has already been used for service "
855 + cfg.getServiceReference() + " and will now also be given to " + sr, null );
856 }
857 else
858 {
859 // assign the configuration to the service
860 cfg.setServiceReference( sr );
861 }
862
863 // prepare the configuration for the service (call plugins)
864 dictionary = callPlugins( sr, cfg );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000865 }
866 else
867 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000868 // 104.5.3 ManagedService.updated must be called with null
869 // if no configuration is available
870 dictionary = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000871 }
872
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000873 // update the service with the configuration
874 try
875 {
876 service.updated( dictionary );
877 }
878 catch ( ConfigurationException ce )
879 {
880 if ( ce.getProperty() != null )
881 {
882 log( LogService.LOG_ERROR, sr + ": Updating configuration property " + ce.getProperty()
883 + " caused a problem: " + ce.getReason(), ce );
884 }
885 else
886 {
887 log( LogService.LOG_ERROR, sr + ": Updating configuration caused a problem: " + ce.getReason(), ce );
888
889 }
890 }
891 catch ( Throwable t )
892 {
893 log( LogService.LOG_ERROR, sr + ": Unexpected problem updating configuration", t );
894 }
895
896 // 104.5.3 CM_UPDATED is sent asynchronously to all
897 // ConfigurationListeners
Felix Meschberger66423332007-08-22 08:46:34 +0000898 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, pid, null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000899 }
900 }
901
902 private class ManagedServiceFactoryUpdate implements Runnable
903 {
904 private String factoryPid;
905
906 private ServiceReference sr;
907
908 private ManagedServiceFactory service;
909
910
911 ManagedServiceFactoryUpdate( String factoryPid, ServiceReference sr, ManagedServiceFactory service )
912 {
913 this.factoryPid = factoryPid;
914 this.sr = sr;
915 this.service = service;
916 }
917
918
919 public void run()
920 {
921 Factory factory;
922 try
923 {
924 factory = getFactory( factoryPid );
925 }
926 catch ( IOException ioe )
927 {
928 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID " + factoryPid, ioe );
929 return;
930 }
931
932 String bundleLocation = sr.getBundle().getLocation();
933 if ( factory.getBundleLocation() == null )
934 {
935 // bind to the location of the service if unbound
936 factory.setBundleLocation( bundleLocation );
937 }
938 else if ( !bundleLocation.equals( factory.getBundleLocation() ) )
939 {
940 // factory PID is bound to another bundle
941 log( LogService.LOG_ERROR, "Cannot use Factory configuration for " + factoryPid
942 + " requested by bundle " + sr.getBundle().getLocation() + " but belongs to "
943 + factory.getBundleLocation(), null );
944 return;
945 }
946
947 Set pids = factory.getPIDs();
948
949 for ( Iterator pi = pids.iterator(); pi.hasNext(); )
950 {
951 String pid = ( String ) pi.next();
952 ConfigurationImpl cfg;
953 try
954 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000955 cfg = getExistingConfiguration( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000956 }
957 catch ( IOException ioe )
958 {
959 log( LogService.LOG_ERROR, "Error loading configuration for " + pid, ioe );
960 continue;
961 }
962
963 // sanity check on the configuration
964 if ( cfg == null )
965 {
966 log( LogService.LOG_ERROR, "Configuration " + pid + " referred to by factory " + factoryPid
967 + " does not exist", null );
968 factory.removePID( pid );
969 factory.storeSilently();
970 continue;
971 }
Felix Meschberger2941ef92007-08-20 13:15:16 +0000972 else if ( cfg.isNew() )
973 {
974 // Configuration has just been created but not yet updated
975 // we currently just ignore it and have the update mechanism
976 // provide the configuration to the ManagedServiceFactory
977 continue;
978 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000979 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
980 {
981 log( LogService.LOG_ERROR, "Configuration " + pid + " referred to by factory " + factoryPid
Felix Meschbergerbb048982007-08-06 08:56:50 +0000982 + " seems to belong to factory " + cfg.getFactoryPid(), null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000983 factory.removePID( pid );
984 factory.storeSilently();
985 continue;
986 }
987
988 // check bundle location of configuration
989 if ( cfg.getBundleLocation() == null )
990 {
991 // bind to the location of the service if unbound
992 cfg.setBundleLocation( bundleLocation );
993 }
994 else if ( !bundleLocation.equals( cfg.getBundleLocation() ) )
995 {
996 // configuration is bound to another bundle
997 log( LogService.LOG_ERROR, "Configuration " + pid + " (factory " + factoryPid
998 + ") belongs to bundle " + cfg.getBundleLocation() + " but was requested for bundle "
999 + bundleLocation, null );
1000 continue;
1001 }
1002
1003 // prepare the configuration for the service (call plugins)
1004 Dictionary dictionary = callPlugins( sr, cfg );
1005
1006 // update the service with the configuration
1007 try
1008 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001009 // only, if there is non-null configuration data
1010 if ( dictionary != null )
1011 {
1012 service.updated( pid, dictionary );
1013 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001014 }
1015 catch ( ConfigurationException ce )
1016 {
1017 if ( ce.getProperty() != null )
1018 {
1019 log( LogService.LOG_ERROR, sr + ": Updating configuration property " + ce.getProperty()
1020 + " caused a problem: " + ce.getReason(), ce );
1021 }
1022 else
1023 {
1024 log( LogService.LOG_ERROR, sr + ": Updating configuration caused a problem: " + ce.getReason(),
1025 ce );
1026
1027 }
1028 }
1029 catch ( Throwable t )
1030 {
1031 log( LogService.LOG_ERROR, sr + ": Unexpected problem updating configuration", t );
1032 }
1033 }
1034 }
1035 }
1036
1037 private class UpdateConfiguration implements Runnable
1038 {
1039
1040 private ConfigurationImpl config;
1041
1042
1043 UpdateConfiguration( ConfigurationImpl config )
1044 {
1045 this.config = config;
1046 }
1047
1048
1049 public void run()
1050 {
1051 try
1052 {
1053 if ( config.getFactoryPid() == null )
1054 {
1055 ServiceReference[] sr = bundleContext.getServiceReferences( ManagedService.class.getName(), "("
1056 + Constants.SERVICE_PID + "=" + config.getPid() + ")" );
1057 if ( sr != null && sr.length > 0 )
1058 {
1059 ManagedService srv = ( ManagedService ) bundleContext.getService( sr[0] );
1060 try
1061 {
1062 // bind the configuration, fail if bound to another
1063 // bundle !!
1064 // check bundle location of configuration
1065 String bundleLocation = sr[0].getBundle().getLocation();
1066 if ( config.getBundleLocation() == null )
1067 {
1068 // bind to the location of the service if
1069 // unbound
1070 config.setBundleLocation( bundleLocation );
1071 }
1072 else if ( !bundleLocation.equals( config.getBundleLocation() ) )
1073 {
1074 // configuration is bound to another bundle
1075 log( LogService.LOG_ERROR, "Configuration " + config.getPid() + " belongs to bundle "
1076 + config.getBundleLocation() + " but was requested for bundle " + bundleLocation,
1077 null );
1078 return;
1079 }
1080
Felix Meschbergerbb048982007-08-06 08:56:50 +00001081 // prepare the configuration for the service (call plugins)
1082 Dictionary dictionary = callPlugins( sr[0], config );
1083
1084 // update the ManagedService with the properties
1085 srv.updated( dictionary );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001086 }
1087 finally
1088 {
1089 bundleContext.ungetService( sr[0] );
1090 }
1091 }
1092 }
1093 else
1094 {
1095 ServiceReference[] sr = bundleContext.getServiceReferences( ManagedServiceFactory.class.getName(),
1096 "(" + Constants.SERVICE_PID + "=" + config.getFactoryPid() + ")" );
1097 if ( sr != null && sr.length > 0 )
1098 {
1099 ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext.getService( sr[0] );
1100 try
1101 {
1102 // bind the configuration, fail if bound to another
1103 // bundle !!
1104 // check bundle location of configuration
1105 String bundleLocation = sr[0].getBundle().getLocation();
1106 if ( config.getBundleLocation() == null )
1107 {
1108 // bind to the location of the service if
1109 // unbound
1110 config.setBundleLocation( bundleLocation );
1111 }
1112 else if ( !bundleLocation.equals( config.getBundleLocation() ) )
1113 {
1114 // configuration is bound to another bundle
1115 log( LogService.LOG_ERROR, "Configuration " + config.getPid() + " (factory "
1116 + config.getFactoryPid() + ") belongs to bundle " + config.getBundleLocation()
1117 + " but was requested for bundle " + bundleLocation, null );
1118 return;
1119 }
1120
Felix Meschbergerbb048982007-08-06 08:56:50 +00001121
1122 // prepare the configuration for the service (call plugins)
1123 Dictionary dictionary = callPlugins( sr[0], config );
1124
1125 // update the ManagedServiceFactory with the properties
Felix Meschberger2941ef92007-08-20 13:15:16 +00001126 // only, if there is non-null configuration data
1127 if ( dictionary != null )
1128 {
1129 srv.updated( config.getPid(), dictionary );
1130 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001131 }
1132 finally
1133 {
1134 bundleContext.ungetService( sr[0] );
1135 }
1136 }
1137 }
1138 }
1139 catch ( ConfigurationException ce )
1140 {
1141 if ( ce.getProperty() != null )
1142 {
1143 log( LogService.LOG_ERROR, "Updating configuration property " + ce.getProperty()
1144 + " caused a problem: " + ce.getReason(), ce );
1145 }
1146 else
1147 {
1148 log( LogService.LOG_ERROR, "Updating configuration caused a problem: " + ce.getReason(), ce );
1149
1150 }
1151 }
1152 catch ( Throwable t )
1153 {
1154 log( LogService.LOG_ERROR, "Unexpected problem updating configuration", t );
1155 }
1156
Felix Meschberger66423332007-08-22 08:46:34 +00001157 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPid(), config.getFactoryPid() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001158 }
1159 }
1160
1161 private class DeleteConfiguration implements Runnable
1162 {
Felix Meschberger66423332007-08-22 08:46:34 +00001163
1164 private String pid;
1165 private String factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001166
1167
1168 DeleteConfiguration( ConfigurationImpl config )
1169 {
Felix Meschberger66423332007-08-22 08:46:34 +00001170 this.pid = config.getPid();
1171 this.factoryPid = config.getFactoryPid();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001172 }
1173
1174
1175 public void run()
1176 {
1177 try
1178 {
Felix Meschberger66423332007-08-22 08:46:34 +00001179 if ( factoryPid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001180 {
1181 ServiceReference[] sr = bundleContext.getServiceReferences( ManagedService.class.getName(), "("
Felix Meschberger66423332007-08-22 08:46:34 +00001182 + Constants.SERVICE_PID + "=" + pid + ")" );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001183 if ( sr != null && sr.length > 0 )
1184 {
1185 ManagedService srv = ( ManagedService ) bundleContext.getService( sr[0] );
1186 try
1187 {
1188 srv.updated( null );
1189 }
1190 finally
1191 {
1192 bundleContext.ungetService( sr[0] );
1193 }
1194 }
1195 }
1196 else
1197 {
1198 // remove the pid from the factory
Felix Meschberger66423332007-08-22 08:46:34 +00001199 Factory factory = getFactory( factoryPid );
1200 factory.removePID( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001201 factory.store();
1202
1203 ServiceReference[] sr = bundleContext.getServiceReferences( ManagedServiceFactory.class.getName(),
Felix Meschberger66423332007-08-22 08:46:34 +00001204 "(" + Constants.SERVICE_PID + "=" + factoryPid + ")" );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001205 if ( sr != null && sr.length > 0 )
1206 {
1207 ManagedServiceFactory srv = ( ManagedServiceFactory ) bundleContext.getService( sr[0] );
1208 try
1209 {
Felix Meschberger66423332007-08-22 08:46:34 +00001210 srv.deleted( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001211 }
1212 finally
1213 {
1214 bundleContext.ungetService( sr[0] );
1215 }
1216 }
1217 }
1218 }
1219 catch ( ConfigurationException ce )
1220 {
1221 if ( ce.getProperty() != null )
1222 {
1223 log( LogService.LOG_ERROR, "Updating configuration property " + ce.getProperty()
1224 + " caused a problem: " + ce.getReason(), ce );
1225 }
1226 else
1227 {
1228 log( LogService.LOG_ERROR, "Updating configuration caused a problem: " + ce.getReason(), ce );
1229
1230 }
1231 }
1232 catch ( Throwable t )
1233 {
1234 log( LogService.LOG_ERROR, "Unexpected problem updating configuration", t );
1235 }
1236
Felix Meschberger66423332007-08-22 08:46:34 +00001237 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, pid, factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001238 }
1239 }
1240
1241 private class FireConfigurationEvent implements Runnable
1242 {
1243 private int type;
1244
Felix Meschberger66423332007-08-22 08:46:34 +00001245 private String pid;
1246
1247 private String factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001248
1249
Felix Meschberger66423332007-08-22 08:46:34 +00001250 FireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001251 {
1252 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001253 this.pid = pid;
1254 this.factoryPid = factoryPid;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001255 }
1256
1257
1258 public void run()
1259 {
1260 // get the listeners
1261 ServiceReference[] srs = configurationListenerTracker.getServiceReferences();
1262 if ( srs == null || srs.length == 0 )
1263 {
1264 return;
1265 }
1266
Felix Meschberger66423332007-08-22 08:46:34 +00001267 ConfigurationEvent event = new ConfigurationEvent( configurationAdminReference, type, factoryPid, pid);
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001268
1269 for ( int i = 0; i < srs.length; i++ )
1270 {
1271 ConfigurationListener cl = ( ConfigurationListener ) configurationListenerTracker.getService( srs[i] );
1272 try
1273 {
1274 cl.configurationEvent( event );
1275 }
1276 catch ( Throwable t )
1277 {
1278 log( LogService.LOG_ERROR, "Unexpected problem delivery configuration event to " + srs[i], t );
1279 }
1280 }
1281 }
1282 }
1283
1284 private abstract class AbstractManagedServiceTracker extends ServiceTracker
1285 {
1286 AbstractManagedServiceTracker( String className )
1287 {
1288 super( bundleContext, className, null );
1289 open();
1290 }
1291
1292
1293 public void removedService( ServiceReference reference, Object service )
1294 {
1295 // check whether we can take back the configuration object
1296 String pid = ( String ) reference.getProperty( Constants.SERVICE_PID );
1297 if ( pid != null )
1298 {
1299 ConfigurationImpl cfg = getCachedConfiguration( pid );
1300 if ( cfg != null && reference.equals( cfg.getServiceReference() ) )
1301 {
1302 cfg.setServiceReference( null );
1303 }
1304 }
1305
1306 super.removedService( reference, service );
1307 }
1308 }
1309
1310 private class ManagedServiceTracker extends AbstractManagedServiceTracker
1311 {
1312 ManagedServiceTracker()
1313 {
1314 super( ManagedService.class.getName() );
1315 }
1316
1317
1318 public Object addingService( ServiceReference reference )
1319 {
1320 ManagedService service = ( ManagedService ) super.addingService( reference );
1321
1322 // configure the managed service
1323 if ( service != null )
1324 {
1325 configure( reference, service );
1326 }
1327
1328 return service;
1329 }
1330 }
1331
1332 private class ManagedServiceFactoryTracker extends AbstractManagedServiceTracker
1333 {
1334 ManagedServiceFactoryTracker()
1335 {
1336 super( ManagedServiceFactory.class.getName() );
1337 }
1338
1339
1340 public Object addingService( ServiceReference reference )
1341 {
1342 ManagedServiceFactory service = ( ManagedServiceFactory ) super.addingService( reference );
1343
1344 // configure the managed service
1345 if ( service != null )
1346 {
1347 configure( reference, service );
1348 }
1349
1350 return service;
1351 }
1352 }
1353}