blob: d9dc3ab30d3a7e6d741c1001f54d0e0ff2cbdf80 [file] [log] [blame]
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001/*
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.apache.felix.cm.impl;
20
21
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000022import java.io.IOException;
23import java.security.SecureRandom;
Felix Meschberger4f269292011-10-21 13:52:31 +000024import java.text.MessageFormat;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000025import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.Dictionary;
28import java.util.Enumeration;
29import java.util.HashMap;
30import java.util.Hashtable;
31import java.util.Iterator;
Felix Meschbergerc0894f32012-07-04 08:09:55 +000032import java.util.LinkedList;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000033import java.util.List;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000034import java.util.Random;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000035
36import org.apache.felix.cm.PersistenceManager;
37import org.apache.felix.cm.file.FilePersistenceManager;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000038import org.apache.felix.cm.impl.helper.BaseTracker;
Felix Meschberger3cbf4652012-10-18 06:49:39 +000039import org.apache.felix.cm.impl.helper.ConfigurationMap;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000040import org.apache.felix.cm.impl.helper.ManagedServiceFactoryTracker;
41import org.apache.felix.cm.impl.helper.ManagedServiceTracker;
42import org.apache.felix.cm.impl.helper.TargetedPID;
43import org.osgi.framework.Bundle;
44import org.osgi.framework.BundleActivator;
45import org.osgi.framework.BundleContext;
46import org.osgi.framework.BundleEvent;
47import org.osgi.framework.BundleListener;
48import org.osgi.framework.Constants;
49import org.osgi.framework.Filter;
50import org.osgi.framework.InvalidSyntaxException;
51import org.osgi.framework.ServiceReference;
52import org.osgi.framework.ServiceRegistration;
53import org.osgi.service.cm.ConfigurationAdmin;
54import org.osgi.service.cm.ConfigurationEvent;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000055import org.osgi.service.cm.ConfigurationListener;
56import org.osgi.service.cm.ConfigurationPermission;
57import org.osgi.service.cm.ConfigurationPlugin;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000058import org.osgi.service.cm.SynchronousConfigurationListener;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000059import org.osgi.service.log.LogService;
60import org.osgi.util.tracker.ServiceTracker;
61
62
63/**
64 * The <code>ConfigurationManager</code> is the central class in this
65 * implementation of the Configuration Admin Service Specification. As such it
66 * has the following tasks:
67 * <ul>
68 * <li>It is a <code>BundleActivator</code> which is called when the bundle
69 * is started and stopped.
70 * <li>It is a <code>BundleListener</code> which gets informed when the
71 * states of bundles change. Mostly this is needed to unbind any bound
72 * configuration in case a bundle is uninstalled.
73 * <li>It is a <code>ServiceListener</code> which gets informed when
74 * <code>ManagedService</code> and <code>ManagedServiceFactory</code>
75 * services are registered and unregistered. This is used to provide
76 * configuration to these services. As a service listener it also listens for
77 * {@link PersistenceManager} instances being registered to support different
78 * configuration persistence layers.
79 * <li>A {@link ConfigurationAdminFactory} instance is registered as the
80 * <code>ConfigurationAdmin</code> service.
81 * <li>A {@link FilePersistenceManager} instance is registered as a default
82 * {@link PersistenceManager}.
83 * <li>Last but not least this instance manages all tasks laid out in the
84 * specification such as maintaining configuration, taking care of configuration
85 * events, etc.
86 * </ul>
87 * <p>
88 * The default {@link FilePersistenceManager} is configured with a configuration
89 * location taken from the <code>felix.cm.dir</code> framework property. If
90 * this property is not set the <code>config</code> directory in the current
91 * working directory as specified in the <code>user.dir</code> system property
92 * is used.
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000093 */
94public class ConfigurationManager implements BundleActivator, BundleListener
95{
96
97 /**
98 * The name of the bundle context property defining the location for the
99 * configuration files (value is "felix.cm.dir").
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000100 *
Carsten Ziegeler7853b9a2008-01-11 16:30:24 +0000101 * @see #start(BundleContext)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000102 */
103 public static final String CM_CONFIG_DIR = "felix.cm.dir";
104
Felix Meschberger08282c32009-01-28 07:01:55 +0000105 /**
106 * The name of the bundle context property defining the maximum log level
107 * (value is "felix.cm.loglevel"). The log level setting is only used if
108 * there is no OSGi LogService available. Otherwise this setting is ignored.
109 * <p>
110 * This value of this property is expected to be an integer number
111 * corresponding to the log level values of the OSGi LogService. That is 1
112 * for errors, 2 for warnings, 3 for informational messages and 4 for debug
113 * messages. The default value is 2, such that only warnings and errors are
114 * logged in the absence of a LogService.
115 */
116 public static final String CM_LOG_LEVEL = "felix.cm.loglevel";
117
Felix Meschberger85b355d2007-08-31 07:17:38 +0000118 // The name of the LogService (not using the class, which might be missing)
119 private static final String LOG_SERVICE_NAME = "org.osgi.service.log.LogService";
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000120
Felix Meschberger08282c32009-01-28 07:01:55 +0000121 private static final int CM_LOG_LEVEL_DEFAULT = 2;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000122
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000123 // random number generator to create configuration PIDs for factory
124 // configurations
Felix Meschberger417f66c2011-02-04 11:25:23 +0000125 private static Random numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000126
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000127 // the BundleContext of the Configuration Admin Service bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000128 BundleContext bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000129
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000130 // the service registration of the configuration admin
Felix Meschberger4b26df92011-02-01 12:41:45 +0000131 private volatile ServiceRegistration configurationAdminRegistration;
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000132
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000133 // the ServiceTracker to emit log services (see log(int, String, Throwable))
134 private ServiceTracker logTracker;
135
136 // the ConfigurationEvent listeners
137 private ServiceTracker configurationListenerTracker;
138
Felix Meschbergere94b1572012-07-14 11:59:29 +0000139 // the synchronous ConfigurationEvent listeners
140 private ServiceTracker syncConfigurationListenerTracker;
141
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000142 // service tracker for managed services
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000143 private ManagedServiceTracker managedServiceTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000144
145 // service tracker for managed service factories
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000146 private ManagedServiceFactoryTracker managedServiceFactoryTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000147
148 // PersistenceManager services
149 private ServiceTracker persistenceManagerTracker;
150
151 // the thread used to schedule tasks required to run asynchronously
152 private UpdateThread updateThread;
153
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000154 // the thread used to schedule events to be dispatched asynchronously
155 private UpdateThread eventThread;
156
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000157 /**
158 * The actual list of {@link PersistenceManager persistence managers} to use
159 * when looking for configuration data. This list is built from the
160 * {@link #persistenceManagerMap}, which is ordered according to the
161 * {@link RankingComparator}.
162 */
163 private PersistenceManager[] persistenceManagers;
164
165 // the persistenceManagerTracker.getTrackingCount when the
166 // persistenceManagers were last got
167 private int pmtCount;
168
169 // the cache of Factory instances mapped by their factory PID
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000170 private final HashMap<String, Factory> factories = new HashMap<String, Factory>();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000171
172 // the cache of Configuration instances mapped by their PID
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000173 // have this always set to prevent NPE on bundle shutdown
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000174 private final HashMap<String, ConfigurationImpl> configurations = new HashMap<String, ConfigurationImpl>();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000175
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000176 /**
177 * The map of dynamic configuration bindings. This maps the
178 * PID of the dynamically bound configuration or factory to its bundle
179 * location.
180 * <p>
181 * On bundle startup this map is loaded from persistence and validated
182 * against the locations of installed bundles: Entries pointing to bundle
183 * locations not currently installed are removed.
184 * <p>
185 * The map is written to persistence on each change.
186 */
187 private DynamicBindings dynamicBindings;
188
Felix Meschberger08282c32009-01-28 07:01:55 +0000189 // the maximum log level when no LogService is available
190 private int logLevel = CM_LOG_LEVEL_DEFAULT;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000191
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000192 // flag indicating whether BundleChange events should be consumed (FELIX-979)
193 private volatile boolean handleBundleEvents;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000194
Felix Meschberger623f7142012-01-31 07:13:37 +0000195 // flag indicating whether the manager is considered alive
196 private volatile boolean isActive;
197
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000198 public void start( BundleContext bundleContext )
199 {
200 // track the log service using a ServiceTracker
Felix Meschberger85b355d2007-08-31 07:17:38 +0000201 logTracker = new ServiceTracker( bundleContext, LOG_SERVICE_NAME , null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000202 logTracker.open();
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000203
Felix Meschberger08282c32009-01-28 07:01:55 +0000204 // assign the log level
205 String logLevelProp = bundleContext.getProperty( CM_LOG_LEVEL );
206 if ( logLevelProp == null )
207 {
208 logLevel = CM_LOG_LEVEL_DEFAULT;
209 }
210 else
211 {
212 try
213 {
214 logLevel = Integer.parseInt( logLevelProp );
215 }
216 catch ( NumberFormatException nfe )
217 {
218 logLevel = CM_LOG_LEVEL_DEFAULT;
219 }
220 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000221
222 // set up some fields
223 this.bundleContext = bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000224
225 // configurationlistener support
226 configurationListenerTracker = new ServiceTracker( bundleContext, ConfigurationListener.class.getName(), null );
227 configurationListenerTracker.open();
Felix Meschbergere94b1572012-07-14 11:59:29 +0000228 syncConfigurationListenerTracker = new ServiceTracker( bundleContext,
229 SynchronousConfigurationListener.class.getName(), null );
230 syncConfigurationListenerTracker.open();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000231
232 // initialize the asynchonous updater thread
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000233 ThreadGroup tg = new ThreadGroup( "Configuration Admin Service" );
234 tg.setDaemon( true );
235 this.updateThread = new UpdateThread( this, tg, "CM Configuration Updater" );
236 this.eventThread = new UpdateThread( this, tg, "CM Event Dispatcher" );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000237
238 // set up the location (might throw IllegalArgumentException)
239 try
240 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000241 FilePersistenceManager fpm = new FilePersistenceManager( bundleContext, bundleContext
242 .getProperty( CM_CONFIG_DIR ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000243 Hashtable props = new Hashtable();
244 props.put( Constants.SERVICE_PID, fpm.getClass().getName() );
245 props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
246 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
247 props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
248 bundleContext.registerService( PersistenceManager.class.getName(), fpm, props );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000249
250 // setup dynamic configuration bindings
251 dynamicBindings = new DynamicBindings( bundleContext, fpm );
252 }
253 catch ( IOException ioe )
254 {
255 log( LogService.LOG_ERROR, "Failure setting up dynamic configuration bindings", ioe );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000256 }
257 catch ( IllegalArgumentException iae )
258 {
259 log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
260 }
261
262 // register as bundle and service listener
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000263 handleBundleEvents = true;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000264 bundleContext.addBundleListener( this );
265
266 // get all persistence managers to begin with
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000267 pmtCount = 1; // make sure to get the persistence managers at least once
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000268 persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
269 persistenceManagerTracker.open();
270
Felix Meschberger623f7142012-01-31 07:13:37 +0000271 // consider alive now (before clients use Configuration Admin
272 // service registered in the next step)
273 isActive = true;
274
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000275 // create and register configuration admin - start after PM tracker ...
276 ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
277 Hashtable props = new Hashtable();
278 props.put( Constants.SERVICE_PID, "org.apache.felix.cm.ConfigurationAdmin" );
279 props.put( Constants.SERVICE_DESCRIPTION, "Configuration Admin Service Specification 1.2 Implementation" );
280 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000281 configurationAdminRegistration = bundleContext.registerService( ConfigurationAdmin.class.getName(), caf, props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000282
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000283 // start handling ManagedService[Factory] services
284 managedServiceTracker = new ManagedServiceTracker(this);
285 managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this);
286
Felix Meschberger4b26df92011-02-01 12:41:45 +0000287 // start processing the event queues only after registering the service
288 // see FELIX-2813 for details
289 this.updateThread.start();
290 this.eventThread.start();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000291 }
292
293
294 public void stop( BundleContext bundleContext )
295 {
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000296
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000297 // stop handling bundle events immediately
298 handleBundleEvents = false;
299
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000300 // stop handling ManagedService[Factory] services
301 managedServiceFactoryTracker.close();
302 managedServiceTracker.close();
303
Felix Meschberger4b26df92011-02-01 12:41:45 +0000304 // stop queue processing before unregistering the service
305 // see FELIX-2813 for details
306 if ( updateThread != null )
307 {
308 updateThread.terminate();
309 }
310 if ( eventThread != null )
311 {
312 eventThread.terminate();
313 }
314
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000315 // immediately unregister the Configuration Admin before cleaning up
Felix Meschberger10568352009-01-15 08:57:11 +0000316 // clearing the field before actually unregistering the service
317 // prevents IllegalStateException in getServiceReference() if
318 // the field is not null but the service already unregistered
319 if (configurationAdminRegistration != null) {
320 ServiceRegistration reg = configurationAdminRegistration;
321 configurationAdminRegistration = null;
322 reg.unregister();
323 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000324
Felix Meschberger623f7142012-01-31 07:13:37 +0000325 // consider inactive after unregistering such that during
326 // unregistration the manager is still alive and can react
327 isActive = false;
328
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000329 // don't care for PersistenceManagers any more
330 persistenceManagerTracker.close();
331
332 // stop listening for events
333 bundleContext.removeBundleListener( this );
334
335 if ( configurationListenerTracker != null )
336 {
337 configurationListenerTracker.close();
338 }
339
Felix Meschbergere94b1572012-07-14 11:59:29 +0000340 if ( syncConfigurationListenerTracker != null )
341 {
342 syncConfigurationListenerTracker.close();
343 }
344
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000345 if ( logTracker != null )
346 {
347 logTracker.close();
348 }
349
Felix Meschberger6a698df2009-08-16 18:38:46 +0000350 // just ensure the configuration cache is empty
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000351 synchronized ( configurations )
352 {
353 configurations.clear();
354 }
355
Felix Meschberger6a698df2009-08-16 18:38:46 +0000356 // just ensure the factory cache is empty
357 synchronized ( factories )
358 {
359 factories.clear();
360 }
361
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000362 this.bundleContext = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000363 }
364
365
Felix Meschberger623f7142012-01-31 07:13:37 +0000366 /**
367 * Returns <code>true</code> if this manager is considered active.
368 */
369 boolean isActive()
370 {
371 return isActive;
372 }
373
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000374 public BundleContext getBundleContext()
375 {
376 return bundleContext;
377 }
Felix Meschberger623f7142012-01-31 07:13:37 +0000378
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000379 // ---------- Configuration caching support --------------------------------
380
381 ConfigurationImpl getCachedConfiguration( String pid )
382 {
383 synchronized ( configurations )
384 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000385 return configurations.get( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000386 }
387 }
388
389
Felix Meschberger6a698df2009-08-16 18:38:46 +0000390 ConfigurationImpl[] getCachedConfigurations()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000391 {
392 synchronized ( configurations )
393 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000394 return configurations.values().toArray(
Felix Meschberger6a698df2009-08-16 18:38:46 +0000395 new ConfigurationImpl[configurations.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000396 }
397 }
398
399
Felix Meschberger2941ef92007-08-20 13:15:16 +0000400 ConfigurationImpl cacheConfiguration( ConfigurationImpl configuration )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000401 {
402 synchronized ( configurations )
403 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000404 final String pid = configuration.getPidString();
405 final Object existing = configurations.get( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000406 if ( existing != null )
407 {
408 return ( ConfigurationImpl ) existing;
409 }
410
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000411 configurations.put( pid, configuration );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000412 return configuration;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000413 }
414 }
415
416
417 void removeConfiguration( ConfigurationImpl configuration )
418 {
419 synchronized ( configurations )
420 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000421 configurations.remove( configuration.getPidString() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000422 }
423 }
424
425
Felix Meschberger6a698df2009-08-16 18:38:46 +0000426 Factory getCachedFactory( String factoryPid )
427 {
428 synchronized ( factories )
429 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000430 return factories.get( factoryPid );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000431 }
432 }
433
434
435 Factory[] getCachedFactories()
436 {
437 synchronized ( factories )
438 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000439 return factories.values().toArray( new Factory[factories.size()] );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000440 }
441 }
442
443
444 void cacheFactory( Factory factory )
445 {
446 synchronized ( factories )
447 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000448 factories.put( factory.getFactoryPidString(), factory );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000449 }
450 }
451
452
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000453 // ---------- ConfigurationAdminImpl support
Felix Meschberger6a698df2009-08-16 18:38:46 +0000454
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000455 void setDynamicBundleLocation( final String pid, final String location )
456 {
457 if ( dynamicBindings != null )
458 {
459 try
460 {
461 dynamicBindings.putLocation( pid, location );
462 }
463 catch ( IOException ioe )
464 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000465 log( LogService.LOG_ERROR, "Failed storing dynamic configuration binding for {0} to {1}", new Object[]
466 { pid, location, ioe } );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000467 }
468 }
469 }
470
471
472 String getDynamicBundleLocation( final String pid )
473 {
474 if ( dynamicBindings != null )
475 {
476 return dynamicBindings.getLocation( pid );
477 }
478
479 return null;
480 }
481
482
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000483 ConfigurationImpl createFactoryConfiguration( String factoryPid, String location ) throws IOException
484 {
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000485 return cacheConfiguration( createConfiguration( createPid( factoryPid ), factoryPid, location ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000486 }
487
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000488 /**
489 * Returns a targeted configuration for the given service PID and
490 * the reference target service.
Felix Meschberger273985f2012-07-05 12:28:06 +0000491 * <p>
492 * A configuration returned has already been checked for visibility
493 * by the bundle registering the referenced service. Additionally,
494 * the configuration is also dynamically bound if needed.
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000495 *
496 * @param rawPid The raw service PID to get targeted configuration for.
497 * @param target The target <code>ServiceReference</code> to get
498 * configuration for.
499 * @return The best matching targeted configuration or <code>null</code>
500 * if there is no configuration at all.
501 * @throwss IOException if an error occurrs reading configurations
502 * from persistence.
503 */
504 ConfigurationImpl getTargetedConfiguration( final String rawPid, final ServiceReference target ) throws IOException
505 {
506 final Bundle serviceBundle = target.getBundle();
507 if ( serviceBundle != null )
508 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000509 // list of targeted PIDs to check
510 // (StringBuffer for pre-1.5 API compatibility)
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000511 final StringBuffer targetedPid = new StringBuffer( rawPid );
512 int i = 3;
513 String[] names = new String[4];
514 names[i--] = targetedPid.toString();
515 targetedPid.append( '|' ).append( serviceBundle.getSymbolicName() );
516 names[i--] = targetedPid.toString();
517 targetedPid.append( '|' ).append( TargetedPID.getBundleVersion( serviceBundle ) );
518 names[i--] = targetedPid.toString();
519 targetedPid.append( '|' ).append( serviceBundle.getLocation() );
520 names[i--] = targetedPid.toString();
521
522 for ( String candidate : names )
523 {
524 ConfigurationImpl config = getConfiguration( candidate );
Felix Meschbergercd5195f2012-07-05 17:17:45 +0000525 if ( config != null && !config.isDeleted() )
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000526 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000527 // check visibility to use and dynamically bind
528 if ( canReceive( serviceBundle, config.getBundleLocation() ) )
529 {
530 config.tryBindLocation( serviceBundle.getLocation() );
531 return config;
532 }
533
534 // CM 1.4 / 104.13.2.2 / 104.5.3
535 // act as if there is no configuration
536 log(
537 LogService.LOG_DEBUG,
538 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}; calling with null",
539 new Object[]
540 { config.getPid(), toString( target ), config.getBundleLocation() } );
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000541 }
542 }
543 }
Felix Meschberger273985f2012-07-05 12:28:06 +0000544 else
545 {
546 log( LogService.LOG_INFO,
547 "Service for PID {0} seems to already have been unregistered, not updating with configuration",
548 new Object[]
549 { rawPid } );
550 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000551
552 // service already unregistered, nothing to do really
553 return null;
554 }
555
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000556
Felix Meschbergerad949872011-11-16 10:34:54 +0000557 /**
558 * Returns the {@link ConfigurationImpl} with the given PID if
559 * available in the internal cache or from any persistence manager.
560 * Otherwise <code>null</code> is returned.
561 *
562 * @param pid The PID for which to return the configuration
563 * @return The configuration or <code>null</code> if non exists
564 * @throws IOException If an error occurrs reading from a persistence
565 * manager.
566 */
567 ConfigurationImpl getConfiguration( String pid ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000568 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000569 ConfigurationImpl config = getCachedConfiguration( pid );
570 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000571 {
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000572 log( LogService.LOG_DEBUG, "Found cached configuration {0} bound to {1}", new Object[]
573 { pid, config.getBundleLocation() } );
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000574
575 config.ensureFactoryConfigPersisted();
576
Felix Meschberger2941ef92007-08-20 13:15:16 +0000577 return config;
578 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000579
Felix Meschberger2941ef92007-08-20 13:15:16 +0000580 PersistenceManager[] pmList = getPersistenceManagers();
581 for ( int i = 0; i < pmList.length; i++ )
582 {
583 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000584 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000585 Dictionary props = pmList[i].load( pid );
586 config = new ConfigurationImpl( this, pmList[i], props );
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000587 log( LogService.LOG_DEBUG, "Found existing configuration {0} bound to {1}", new Object[]
588 { pid, config.getBundleLocation() } );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000589 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000590 }
591 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000592
Felix Meschberger2941ef92007-08-20 13:15:16 +0000593 // neither the cache nor any persistence manager has configuration
594 return null;
595 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000596
597
Felix Meschbergerad949872011-11-16 10:34:54 +0000598 /**
599 * Creates a regular (non-factory) configuration for the given PID
600 * setting the bundle location accordingly.
601 * <p>
602 * This method assumes the configuration to not exist yet and will
603 * create it without further checking.
604 *
605 * @param pid The PID of the new configuration
606 * @param bundleLocation The location to set on the new configuration.
607 * This may be <code>null</code> to not bind the configuration
608 * yet.
609 * @return The new configuration persisted in the first persistence
610 * manager.
611 * @throws IOException If an error occurrs writing the configuration
612 * to the persistence.
613 */
614 ConfigurationImpl createConfiguration( String pid, String bundleLocation ) throws IOException
Felix Meschberger2941ef92007-08-20 13:15:16 +0000615 {
616 // check for existing (cached or persistent) configuration
Felix Meschbergerad949872011-11-16 10:34:54 +0000617 ConfigurationImpl config = getConfiguration( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000618 if ( config != null )
619 {
620 return config;
621 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000622
Felix Meschberger2941ef92007-08-20 13:15:16 +0000623 // else create new configuration also setting the bundle location
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000624 // and cache the new configuration
625 config = createConfiguration( pid, null, bundleLocation );
626 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000627 }
628
629
630 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
631 throws IOException, InvalidSyntaxException
632 {
633 Filter filter = null;
634 if ( filterString != null )
635 {
636 filter = bundleContext.createFilter( filterString );
637 }
638
Felix Meschberger4f269292011-10-21 13:52:31 +0000639 log( LogService.LOG_DEBUG, "Listing configurations matching {0}", new Object[]
640 { filterString } );
641
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000642 List configList = new ArrayList();
643
644 PersistenceManager[] pmList = getPersistenceManagers();
645 for ( int i = 0; i < pmList.length; i++ )
646 {
647 Enumeration configs = pmList[i].getDictionaries();
648 while ( configs.hasMoreElements() )
649 {
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000650 final Dictionary config = ( Dictionary ) configs.nextElement();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000651
652 // ignore non-Configuration dictionaries
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000653 final String pid = ( String ) config.get( Constants.SERVICE_PID );
Felix Meschberger86a0d172007-07-04 07:15:01 +0000654 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000655 {
656 continue;
657 }
658
Felix Meschberger007c50e2011-10-20 12:39:38 +0000659 // CM 1.4 / 104.13.2.3 Permission required
660 if ( !configurationAdmin.hasPermission( ( String ) config
661 .get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000662 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000663 log(
664 LogService.LOG_DEBUG,
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000665 "Omitting configuration {0}: No permission for bundle {1} on configuration bound to {2}",
Felix Meschberger4f269292011-10-21 13:52:31 +0000666 new Object[]
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000667 { pid, configurationAdmin.getBundle().getLocation(),
Felix Meschberger4f269292011-10-21 13:52:31 +0000668 config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000669 continue;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000670 }
671
672 // check filter
673 if ( filter == null || filter.match( config ) )
674 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000675 // ensure the service.pid and returned a cached config if available
676 ConfigurationImpl cfg = getCachedConfiguration( pid );
677 if ( cfg == null )
678 {
679 cfg = new ConfigurationImpl( this, pmList[i], config );
680 }
681
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000682 // FELIX-611: Ignore configuration objects without props
683 if ( !cfg.isNew() )
684 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000685 log( LogService.LOG_DEBUG, "Adding configuration {0}", new Object[]
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000686 { pid } );
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000687 configList.add( cfg );
688 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000689 else
690 {
691 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Is new", new Object[]
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000692 { pid } );
Felix Meschberger4f269292011-10-21 13:52:31 +0000693 }
694 } else {
695 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Does not match filter", new Object[]
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000696 { pid } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000697 }
698 }
699 }
700
Felix Meschberger8faceff2007-07-04 07:19:48 +0000701 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000702 .size()] );
703 }
704
705
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000706 void deleted( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000707 {
708 // remove the configuration from the cache
709 removeConfiguration( config );
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000710 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000711 updateThread.schedule( new DeleteConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000712 log( LogService.LOG_DEBUG, "DeleteConfiguration({0}) scheduled", new Object[]
713 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000714 }
715
716
Felix Meschbergerce67d732009-08-20 06:26:35 +0000717 void updated( ConfigurationImpl config, boolean fireEvent )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000718 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000719 if ( fireEvent )
720 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000721 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000722 }
723 updateThread.schedule( new UpdateConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000724 log( LogService.LOG_DEBUG, "UpdateConfiguration({0}) scheduled", new Object[]
725 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000726 }
727
728
Felix Meschberger007c50e2011-10-20 12:39:38 +0000729 void locationChanged( ConfigurationImpl config, String oldLocation )
730 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000731 fireConfigurationEvent( ConfigurationEvent.CM_LOCATION_CHANGED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger35658d52011-10-20 21:43:58 +0000732 if ( oldLocation != null && !config.isNew() )
Felix Meschberger007c50e2011-10-20 12:39:38 +0000733 {
734 updateThread.schedule( new LocationChanged( config, oldLocation ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000735 log( LogService.LOG_DEBUG, "LocationChanged({0}, {1}=>{2}) scheduled", new Object[]
736 { config.getPid(), oldLocation, config.getBundleLocation() } );
Felix Meschberger35658d52011-10-20 21:43:58 +0000737 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000738 else
Felix Meschberger35658d52011-10-20 21:43:58 +0000739 {
740 log( LogService.LOG_DEBUG,
Felix Meschberger4f269292011-10-21 13:52:31 +0000741 "LocationChanged not scheduled for {0} (old location is null or configuration is new)", new Object[]
742 { config.getPid() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000743 }
744 }
745
746
Felix Meschberger66423332007-08-22 08:46:34 +0000747 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000748 {
Felix Meschbergere94b1572012-07-14 11:59:29 +0000749 // prevent event senders
750 FireConfigurationEvent asyncSender = new FireConfigurationEvent( this.configurationListenerTracker, type, pid,
751 factoryPid );
752 FireConfigurationEvent syncSender = new FireConfigurationEvent( this.syncConfigurationListenerTracker, type,
753 pid, factoryPid );
754
755 // send synchronous events
756 if ( syncSender.hasConfigurationEventListeners() )
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000757 {
Felix Meschbergere94b1572012-07-14 11:59:29 +0000758 syncSender.run();
759 }
760 else
761 {
762 log( LogService.LOG_DEBUG, "No SynchronousConfigurationListeners to send {0} event to.", new Object[]
763 { syncSender.getTypeName() } );
764 }
765
766 // schedule asynchronous events
767 if ( asyncSender.hasConfigurationEventListeners() )
768 {
769 eventThread.schedule( asyncSender );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000770 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000771 else
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000772 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000773 log( LogService.LOG_DEBUG, "No ConfigurationListeners to send {0} event to.", new Object[]
Felix Meschbergere94b1572012-07-14 11:59:29 +0000774 { asyncSender.getTypeName() } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000775 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000776 }
777
778
779 // ---------- BundleListener -----------------------------------------------
780
781 public void bundleChanged( BundleEvent event )
782 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000783 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000784 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000785 final String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000786
Felix Meschberger6a698df2009-08-16 18:38:46 +0000787 // we only reset dynamic bindings, which are only present in
788 // cached configurations, hence only consider cached configs here
789 final ConfigurationImpl[] configs = getCachedConfigurations();
790 for ( int i = 0; i < configs.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000791 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000792 final ConfigurationImpl cfg = configs[i];
Felix Meschberger41cce522009-08-19 05:54:40 +0000793 if ( location.equals( cfg.getDynamicBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000794 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000795 cfg.setDynamicBundleLocation( null, true );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000796 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000797 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000798 }
799 }
800
801
802 // ---------- internal -----------------------------------------------------
803
804 private PersistenceManager[] getPersistenceManagers()
805 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000806 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
807 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000808 {
809
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000810 List pmList = new ArrayList();
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000811 PersistenceManager[] pm;
812
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000813 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
814 if ( refs == null || refs.length == 0 )
815 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000816 pm = new PersistenceManager[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000817 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000818 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000819 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000820 // sort the references according to the cmRanking property
Felix Meschberger007c50e2011-10-20 12:39:38 +0000821 if ( refs.length > 1 )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000822 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000823 Arrays.sort( refs, RankingComparator.SRV_RANKING );
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000824 }
825
826 // create the service array from the sorted set of referenecs
Felix Meschberger007c50e2011-10-20 12:39:38 +0000827 for ( int i = 0; i < refs.length; i++ )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000828 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000829 Object service = persistenceManagerTracker.getService( refs[i] );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000830 if ( service != null )
831 {
Felix Meschbergera86cdfc2010-08-25 09:32:36 +0000832 pmList.add( new CachingPersistenceManagerProxy( ( PersistenceManager ) service ) );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000833 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000834 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000835
836 pm = ( PersistenceManager[] ) pmList.toArray( new PersistenceManager[pmList.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000837 }
838
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000839 pmtCount = pm.length;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000840 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000841 }
842
843 return persistenceManagers;
844 }
845
846
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000847 private ServiceReference getServiceReference()
848 {
849 ServiceRegistration reg = configurationAdminRegistration;
Felix Meschberger0770cad2012-06-11 12:36:52 +0000850 if (reg != null) {
851 return reg.getReference();
852 }
853
854 // probably called for firing an event during service registration
855 // since we didn't get the service registration yet we use the
856 // service registry to get our service reference
857 BundleContext context = bundleContext;
858 if ( context != null )
859 {
860 try
861 {
862 ServiceReference[] refs = context.getServiceReferences( ConfigurationAdmin.class.getName(), null );
863 if ( refs != null )
864 {
865 for ( int i = 0; i < refs.length; i++ )
866 {
867 if ( refs[i].getBundle().getBundleId() == context.getBundle().getBundleId() )
868 {
869 return refs[i];
870 }
871 }
872 }
873 }
874 catch ( InvalidSyntaxException e )
875 {
876 // unexpected since there is no filter
877 }
878 }
879
880 // service references
881 return null;
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000882 }
883
884
Felix Meschberger05d89e12011-11-03 23:37:10 +0000885 /**
886 * Configures the ManagedService and returns the service.pid
887 * service property as a String[], which may be <code>null</code> if
888 * the ManagedService does not have such a property.
889 */
Felix Meschberger05d89e12011-11-03 23:37:10 +0000890 /**
891 * Configures the ManagedServiceFactory and returns the service.pid
892 * service property as a String[], which may be <code>null</code> if
893 * the ManagedServiceFactory does not have such a property.
894 */
Felix Meschberger382a19b2012-07-03 09:45:14 +0000895 /**
896 * Schedules the configuration of the referenced service with
897 * configuration for the given PID.
898 *
Felix Meschberger273985f2012-07-05 12:28:06 +0000899 * @param pid The list of service PID of the configurations to be
900 * provided to the referenced service.
Felix Meschberger382a19b2012-07-03 09:45:14 +0000901 * @param sr The <code>ServiceReference</code> to the service
902 * to be configured.
903 * @param factory <code>true</code> If the service is considered to
904 * be a <code>ManagedServiceFactory</code>. Otherwise the service
905 * is considered to be a <code>ManagedService</code>.
906 */
Felix Meschberger3cbf4652012-10-18 06:49:39 +0000907 public void configure( String[] pid, ServiceReference sr, final boolean factory, final ConfigurationMap<?> configs )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000908 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000909 if ( this.isLogEnabled( LogService.LOG_DEBUG ) )
910 {
911 this.log( LogService.LOG_DEBUG, "configure(ManagedService {0})", new Object[]
912 { toString( sr ) } );
913 }
914
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000915 Runnable r;
916 if ( factory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000917 {
Felix Meschberger3cbf4652012-10-18 06:49:39 +0000918 r = new ManagedServiceFactoryUpdate( pid, sr, configs );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000919 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000920 else
921 {
Felix Meschberger3cbf4652012-10-18 06:49:39 +0000922 r = new ManagedServiceUpdate( pid, sr, configs );
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000923 }
924 updateThread.schedule( r );
925 log( LogService.LOG_DEBUG, "[{0}] scheduled", new Object[]
926 { r } );
Felix Meschberger851c6412009-08-16 18:43:26 +0000927 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000928
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000929
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000930 /**
931 * Factory method to create a new configuration object. The configuration
932 * object returned is not stored in configuration cache and only persisted
933 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000934 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000935 * @param pid
936 * The PID of the new configuration object. Must not be
937 * <code>null</code>.
938 * @param factoryPid
939 * The factory PID of the new configuration. Not
Felix Meschberger6a698df2009-08-16 18:38:46 +0000940 * <code>null</code> if the new configuration object belongs to a
941 * factory. The configuration object will not be persisted if
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000942 * this parameter is not <code>null</code>.
943 * @param bundleLocation
944 * The bundle location of the bundle to which the configuration
Felix Meschberger6a698df2009-08-16 18:38:46 +0000945 * belongs or <code>null</code> if the configuration is not bound
946 * yet.
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000947 * @return The new configuration object
948 * @throws IOException
949 * May be thrown if an error occurrs persisting the new
950 * configuration object.
951 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000952 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000953 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000954 log( LogService.LOG_DEBUG, "createConfiguration({0}, {1}, {2})", new Object[]
955 { pid, factoryPid, bundleLocation } );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000956 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000957 }
958
959
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000960 /**
961 * Returns a list of {@link Factory} instances according to the
962 * Configuration Admin 1.5 specification for targeted PIDs (Section
963 * 104.3.2)
964 *
965 * @param rawFactoryPid The raw factory PID without any targetting.
966 * @param target The <code>ServiceReference</code> of the service to
967 * be supplied with targeted configuration.
968 * @return A list of {@link Factory} instances as listed above. This
969 * list will always at least include an instance for the
970 * <code>rawFactoryPid</code>. Other instances are only included
971 * if existing.
972 * @throws IOException If an error occurrs reading any of the
973 * {@link Factory} instances from persistence
974 */
975 List<Factory> getTargetedFactories( final String rawFactoryPid, final ServiceReference target ) throws IOException
976 {
977 LinkedList<Factory> factories = new LinkedList<Factory>();
978
979 final Bundle serviceBundle = target.getBundle();
980 if ( serviceBundle != null )
981 {
982 // for pre-1.5 API compatibility
983 final StringBuffer targetedPid = new StringBuffer( rawFactoryPid );
984 factories.add( getOrCreateFactory( targetedPid.toString() ) );
985
986 targetedPid.append( '|' ).append( serviceBundle.getSymbolicName() );
987 Factory f = getFactory( targetedPid.toString() );
988 if ( f != null )
989 {
990 factories.add( 0, f );
991 }
992
993 targetedPid.append( '|' ).append( TargetedPID.getBundleVersion( serviceBundle ) );
994 f = getFactory( targetedPid.toString() );
995 if ( f != null )
996 {
997 factories.add( 0, f );
998 }
999
1000 targetedPid.append( '|' ).append( serviceBundle.getLocation() );
1001 f = getFactory( targetedPid.toString() );
1002 if ( f != null )
1003 {
1004 factories.add( 0, f );
1005 }
1006 }
1007
1008 return factories;
1009 }
1010
1011
1012 /**
1013 * Gets the factory with the exact identifier from the cached or from
1014 * the persistence managers. If no factory exists already one is
1015 * created and cached.
1016 *
1017 * @param factoryPid The PID of the {@link Factory} to return
1018 * @return The existing or newly created {@link Factory}
1019 * @throws IOException If an error occurrs reading the factory from
1020 * a {@link PersistenceManager}
1021 */
1022 Factory getOrCreateFactory( String factoryPid ) throws IOException
1023 {
1024 Factory factory = getFactory( factoryPid );
1025 if ( factory != null )
1026 {
1027 return factory;
1028 }
1029
1030 return createFactory( factoryPid );
1031 }
1032
1033
1034 /**
1035 * Gets the factory with the exact identifier from the cached or from
1036 * the persistence managers. If no factory exists <code>null</code>
1037 * is returned.
1038 *
1039 * @param factoryPid The PID of the {@link Factory} to return
1040 * @return The existing {@link Factory} or <code>null</code>
1041 * @throws IOException If an error occurrs reading the factory from
1042 * a {@link PersistenceManager}
1043 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001044 Factory getFactory( String factoryPid ) throws IOException
1045 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001046 // check for cached factory
Felix Meschbergerf4631322008-03-10 12:32:35 +00001047 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001048 if ( factory != null )
1049 {
1050 return factory;
1051 }
1052
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001053 // try to load factory from persistence
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001054 PersistenceManager[] pmList = getPersistenceManagers();
1055 for ( int i = 0; i < pmList.length; i++ )
1056 {
1057 if ( Factory.exists( pmList[i], factoryPid ) )
1058 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +00001059 factory = Factory.load( this, pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001060 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001061 return factory;
1062 }
1063 }
1064
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001065 // no existing factory
1066 return null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001067 }
1068
1069
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001070 /**
1071 * Creates a new factory with the given <code>factoryPid</code>.
1072 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001073 Factory createFactory( String factoryPid )
1074 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +00001075 Factory factory = new Factory( this, getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001076 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001077 return factory;
1078 }
1079
1080
Felix Meschberger2941ef92007-08-20 13:15:16 +00001081 /**
1082 * Calls the registered configuration plugins on the given configuration
Felix Meschberger273985f2012-07-05 12:28:06 +00001083 * properties from the given configuration object.
1084 * <p>
1085 * The plugins to be called are selected as <code>ConfigurationPlugin</code>
1086 * services registered with a <code>cm.target</code> property set to
1087 * <code>*</code> or the factory PID of the configuration (for factory
1088 * configurations) or the PID of the configuration (for non-factory
1089 * configurations).
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001090 *
Felix Meschberger41cce522009-08-19 05:54:40 +00001091 * @param props The configuraiton properties run through the registered
Felix Meschberger273985f2012-07-05 12:28:06 +00001092 * ConfigurationPlugin services. This must not be
1093 * <code>null</code>.
Felix Meschberger2941ef92007-08-20 13:15:16 +00001094 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001095 * is to be updated with configuration
Felix Meschberger273985f2012-07-05 12:28:06 +00001096 * @param configPid The PID of the configuration object whose properties
1097 * are to be augmented
1098 * @param factoryPid the factory PID of the configuration object whose
1099 * properties are to be augmented. This is non-<code>null</code>
1100 * only for a factory configuration.
Felix Meschberger2941ef92007-08-20 13:15:16 +00001101 */
Felix Meschberger273985f2012-07-05 12:28:06 +00001102 public void callPlugins( final Dictionary props, final ServiceReference sr, final String configPid,
1103 final String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001104 {
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001105 ServiceReference[] plugins = null;
1106 try
1107 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001108 final String targetPid = (factoryPid == null) ? configPid : factoryPid;
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001109 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001110 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001111 }
1112 catch ( InvalidSyntaxException ise )
1113 {
1114 // no filter, no exception ...
1115 }
1116
1117 // abort early if there are no plugins
1118 if ( plugins == null || plugins.length == 0 )
1119 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001120 return;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001121 }
1122
1123 // sort the plugins by their service.cmRanking
Felix Meschberger007c50e2011-10-20 12:39:38 +00001124 if ( plugins.length > 1 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001125 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001126 Arrays.sort( plugins, RankingComparator.CM_RANKING );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001127 }
1128
1129 // call the plugins in order
Felix Meschberger007c50e2011-10-20 12:39:38 +00001130 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001131 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001132 ServiceReference pluginRef = plugins[i];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001133 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001134 if ( plugin != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001135 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001136 try
1137 {
1138 plugin.modifyConfiguration( sr, props );
1139 }
1140 catch ( Throwable t )
1141 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001142 log( LogService.LOG_ERROR, "Unexpected problem calling configuration plugin {0}", new Object[]
1143 { toString( pluginRef ), t } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001144 }
1145 finally
1146 {
1147 // ensure ungetting the plugin
1148 bundleContext.ungetService( pluginRef );
1149 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001150 ConfigurationImpl.setAutoProperties( props, configPid, factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001151 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001152 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001153 }
1154
1155
1156 /**
1157 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001158 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001159 * @param factoryPid
1160 * @return
1161 */
1162 private static String createPid( String factoryPid )
1163 {
Felix Meschberger417f66c2011-02-04 11:25:23 +00001164 Random ng = numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001165 if ( ng == null )
1166 {
Felix Meschberger417f66c2011-02-04 11:25:23 +00001167 // FELIX-2771 Secure Random not available on Mika
1168 try
1169 {
1170 ng = new SecureRandom();
1171 }
1172 catch ( Throwable t )
1173 {
1174 // fall back to Random
1175 ng = new Random();
1176 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001177 }
1178
1179 byte[] randomBytes = new byte[16];
1180 ng.nextBytes( randomBytes );
1181 randomBytes[6] &= 0x0f; /* clear version */
1182 randomBytes[6] |= 0x40; /* set to version 4 */
1183 randomBytes[8] &= 0x3f; /* clear variant */
1184 randomBytes[8] |= 0x80; /* set to IETF variant */
1185
1186 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
1187
1188 // prefix the new pid with the factory pid
1189 buf.append( factoryPid ).append( "." );
1190
1191 // serialize the UUID into the buffer
1192 for ( int i = 0; i < randomBytes.length; i++ )
1193 {
1194
1195 if ( i == 4 || i == 6 || i == 8 || i == 10 )
1196 {
1197 buf.append( '-' );
1198 }
1199
1200 int val = randomBytes[i] & 0xff;
1201 buf.append( Integer.toHexString( val >> 4 ) );
1202 buf.append( Integer.toHexString( val & 0xf ) );
1203 }
1204
1205 return buf.toString();
1206 }
1207
1208
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001209 public boolean isLogEnabled( int level )
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001210 {
1211 return level <= logLevel;
1212 }
1213
1214
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001215 public void log( int level, String format, Object[] args )
Felix Meschberger4f269292011-10-21 13:52:31 +00001216 {
1217 if ( isLogEnabled( level ) )
1218 {
1219 Throwable throwable = null;
1220 String message = format;
1221
1222 if ( args != null && args.length > 0 )
1223 {
1224 if ( args[args.length - 1] instanceof Throwable )
1225 {
1226 throwable = ( Throwable ) args[args.length - 1];
1227 }
1228 message = MessageFormat.format( format, args );
1229 }
1230
1231 log( level, message, throwable );
1232 }
1233 }
1234
1235
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001236 public void log( int level, String message, Throwable t )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001237 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001238 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +00001239 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001240 if ( log != null )
1241 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +00001242 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001243 return;
1244 }
1245
Felix Meschberger08282c32009-01-28 07:01:55 +00001246 // Otherwise only log if more serious than the configured level
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001247 if ( isLogEnabled( level ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001248 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001249 String code;
1250 switch ( level )
1251 {
1252 case LogService.LOG_INFO:
1253 code = "*INFO *";
1254 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001255
Felix Meschberger08282c32009-01-28 07:01:55 +00001256 case LogService.LOG_WARNING:
1257 code = "*WARN *";
1258 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001259
Felix Meschberger08282c32009-01-28 07:01:55 +00001260 case LogService.LOG_ERROR:
1261 code = "*ERROR*";
1262 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001263
Felix Meschberger08282c32009-01-28 07:01:55 +00001264 case LogService.LOG_DEBUG:
1265 default:
1266 code = "*DEBUG*";
1267 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001268
Felix Meschberger08282c32009-01-28 07:01:55 +00001269 System.err.println( code + " " + message );
1270 if ( t != null )
1271 {
1272 t.printStackTrace( System.err );
1273 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001274 }
1275 }
1276
Felix Meschberger851c6412009-08-16 18:43:26 +00001277
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001278 public static String toString( ServiceReference ref )
Felix Meschberger41cce522009-08-19 05:54:40 +00001279 {
1280 String[] ocs = ( String[] ) ref.getProperty( "objectClass" );
Felix Meschberger382a19b2012-07-03 09:45:14 +00001281 StringBuffer buf = new StringBuffer( "[" );
Felix Meschberger41cce522009-08-19 05:54:40 +00001282 for ( int i = 0; i < ocs.length; i++ )
1283 {
Felix Meschberger382a19b2012-07-03 09:45:14 +00001284 buf.append( ocs[i] );
Felix Meschberger41cce522009-08-19 05:54:40 +00001285 if ( i < ocs.length - 1 )
Felix Meschberger382a19b2012-07-03 09:45:14 +00001286 buf.append( ", " );
Felix Meschberger41cce522009-08-19 05:54:40 +00001287 }
1288
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001289 buf.append( ", id=" ).append( ref.getProperty( Constants.SERVICE_ID ) );
1290
1291 Bundle provider = ref.getBundle();
1292 if ( provider != null )
1293 {
1294 buf.append( ", bundle=" ).append( provider.getBundleId() );
Felix Meschberger0135b322011-11-16 12:30:22 +00001295 buf.append( '/' ).append( provider.getLocation() );
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001296 }
1297 else
1298 {
1299 buf.append( ", unregistered" );
1300 }
1301
1302 buf.append( "]" );
1303 return buf.toString();
Felix Meschberger41cce522009-08-19 05:54:40 +00001304 }
1305
Felix Meschbergerce67d732009-08-20 06:26:35 +00001306
Felix Meschberger007c50e2011-10-20 12:39:38 +00001307 /**
1308 * Checks whether the bundle is allowed to receive the configuration
1309 * with the given location binding.
1310 * <p>
1311 * This method implements the logic defined CM 1.4 / 104.4.1:
1312 * <ul>
1313 * <li>If the location is <code>null</code> (the configuration is not
1314 * bound yet), assume the bundle is allowed</li>
1315 * <li>If the location is a single location (no leading "?"), require
1316 * the bundle's location to match</li>
1317 * <li>If the location is a multi-location (leading "?"), assume the
1318 * bundle is allowed if there is no security manager. If there is a
1319 * security manager, check whether the bundle has "target" permission
1320 * on this location.</li>
1321 * </ul>
1322 */
1323 boolean canReceive( final Bundle bundle, final String location )
1324 {
1325 if ( location == null )
1326 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001327 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration=(unbound)", new Object[]
Felix Meschberger61207232011-11-17 10:06:45 +00001328 { bundle.getLocation() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001329 return true;
1330 }
1331 else if ( location.startsWith( "?" ) )
1332 {
1333 // multi-location
1334 if ( System.getSecurityManager() != null )
1335 {
Felix Meschberger61207232011-11-17 10:06:45 +00001336 final boolean hasPermission = bundle.hasPermission( new ConfigurationPermission( location,
1337 ConfigurationPermission.TARGET ) );
1338 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2} (SecurityManager check)",
1339 new Object[]
1340 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1341 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001342 }
Felix Meschberger61207232011-11-17 10:06:45 +00001343
1344 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration={1} (no SecurityManager)",
1345 new Object[]
1346 { bundle.getLocation(), location } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001347 return true;
1348 }
1349 else
1350 {
1351 // single location, must match
Felix Meschberger61207232011-11-17 10:06:45 +00001352 final boolean hasPermission = location.equals( bundle.getLocation() );
1353 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2}", new Object[]
1354 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1355 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001356 }
1357 }
1358
Felix Meschberger61207232011-11-17 10:06:45 +00001359
Felix Meschberger007c50e2011-10-20 12:39:38 +00001360 // ---------- inner classes
1361
Felix Meschberger007c50e2011-10-20 12:39:38 +00001362 /**
1363 * The <code>ManagedServiceUpdate</code> updates a freshly registered
1364 * <code>ManagedService</code> with a specific configuration. If a
1365 * ManagedService is registered with multiple PIDs an instance of this
1366 * class is used for each registered PID.
1367 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001368 private class ManagedServiceUpdate implements Runnable
1369 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001370 private final String[] pids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001371
Felix Meschberger41cce522009-08-19 05:54:40 +00001372 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001373
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001374 private final ConfigurationMap<?> configs;
1375
1376
1377 ManagedServiceUpdate( String[] pids, ServiceReference sr, ConfigurationMap<?> configs )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001378 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001379 this.pids = pids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001380 this.sr = sr;
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001381 this.configs = configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001382 }
1383
1384
1385 public void run()
1386 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001387 for ( String pid : this.pids )
1388 {
1389 try
1390 {
1391 final ConfigurationImpl config = getTargetedConfiguration( pid, this.sr );
1392 provide( pid, config );
1393 }
1394 catch ( IOException ioe )
1395 {
1396 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1397 { pid, ioe } );
1398 }
1399 catch ( Exception e )
1400 {
1401 log( LogService.LOG_ERROR, "Unexpected problem providing configuration {0} to service {1}",
1402 new Object[]
1403 { pid, ConfigurationManager.toString( this.sr ), e } );
1404 }
1405 }
1406 }
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001407
Felix Meschberger273985f2012-07-05 12:28:06 +00001408
1409 private void provide(final String servicePid, final ConfigurationImpl config)
1410 {
1411 // check configuration
1412 final TargetedPID configPid;
1413 final Dictionary properties;
1414 final long revision;
Felix Meschberger41cce522009-08-19 05:54:40 +00001415 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001416 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001417 synchronized ( config )
Felix Meschberger41243192009-01-14 19:59:58 +00001418 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001419 configPid = config.getPid();
1420 properties = config.getProperties( true );
1421 revision = config.getRevision();
Felix Meschberger41243192009-01-14 19:59:58 +00001422 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001423 }
1424 else
1425 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001426 // 104.5.3 ManagedService.updated must be called with null
1427 // if no configuration is available
Felix Meschberger273985f2012-07-05 12:28:06 +00001428 configPid = new TargetedPID( servicePid );
Felix Meschberger41cce522009-08-19 05:54:40 +00001429 properties = null;
Felix Meschberger273985f2012-07-05 12:28:06 +00001430 revision = -1;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001431 }
1432
Felix Meschberger273985f2012-07-05 12:28:06 +00001433 log( LogService.LOG_DEBUG, "Updating service {0} with configuration {1}@{2}", new Object[]
1434 { servicePid, configPid, new Long( revision ) } );
1435
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001436 managedServiceTracker.provideConfiguration( sr, configPid, null, properties, revision, this.configs );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001437 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001438
Felix Meschberger432e3872008-03-07 14:58:57 +00001439 public String toString()
1440 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001441 return "ManagedService Update: pid=" + Arrays.asList( pids );
Felix Meschberger432e3872008-03-07 14:58:57 +00001442 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001443 }
1444
Felix Meschberger007c50e2011-10-20 12:39:38 +00001445 /**
1446 * The <code>ManagedServiceFactoryUpdate</code> updates a freshly
1447 * registered <code>ManagedServiceFactory</code> with a specific
1448 * configuration. If a ManagedServiceFactory is registered with
1449 * multiple PIDs an instance of this class is used for each registered
1450 * PID.
1451 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001452 private class ManagedServiceFactoryUpdate implements Runnable
1453 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001454 private final String[] factoryPids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001455
Felix Meschberger41cce522009-08-19 05:54:40 +00001456 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001457
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001458 private final ConfigurationMap<?> configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001459
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001460
1461 ManagedServiceFactoryUpdate( String[] factoryPids, ServiceReference sr, final ConfigurationMap<?> configs )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001462 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001463 this.factoryPids = factoryPids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001464 this.sr = sr;
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001465 this.configs = configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001466 }
1467
1468
1469 public void run()
1470 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001471 for ( String factoryPid : this.factoryPids )
1472 {
1473
1474 List<Factory> factories = null;
1475 try
1476 {
1477 factories = getTargetedFactories( factoryPid, sr );
1478 for ( Factory factory : factories )
1479 {
1480 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
1481 {
1482 final String pid = ( String ) pi.next();
1483 ConfigurationImpl cfg;
1484 try
1485 {
1486 cfg = getConfiguration( pid );
1487 }
1488 catch ( IOException ioe )
1489 {
1490 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1491 { pid, ioe } );
1492 continue;
1493 }
1494
1495 // sanity check on the configuration
1496 if ( cfg == null )
1497 {
1498 log( LogService.LOG_ERROR,
1499 "Configuration {0} referred to by factory {1} does not exist", new Object[]
1500 { pid, factoryPid } );
1501 factory.removePID( pid );
1502 factory.storeSilently();
1503 continue;
1504 }
1505 else if ( cfg.isNew() )
1506 {
1507 // Configuration has just been created but not yet updated
1508 // we currently just ignore it and have the update mechanism
1509 // provide the configuration to the ManagedServiceFactory
1510 // As of FELIX-612 (not storing new factory configurations)
1511 // this should not happen. We keep this for added stability
1512 // but raise the logging level to error.
1513 log( LogService.LOG_ERROR, "Ignoring new configuration pid={0}", new Object[]
1514 { pid } );
1515 continue;
1516 }
1517
1518 /*
1519 * this code would catch targeted factory PIDs;
1520 * since this is not expected any way, we can
1521 * leave this out
1522 */
1523 /*
1524 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1525 {
1526 log( LogService.LOG_ERROR,
1527 "Configuration {0} referred to by factory {1} seems to belong to factory {2}",
1528 new Object[]
1529 { pid, factoryPid, cfg.getFactoryPid() } );
1530 factory.removePID( pid );
1531 factory.storeSilently();
1532 continue;
1533 }
1534 */
1535
1536 provide( factoryPid, cfg );
1537 }
1538 }
1539 }
1540 catch ( IOException ioe )
1541 {
1542 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID {0}", new Object[]
1543 { factoryPid, ioe } );
1544 }
1545 }
1546 }
1547
1548
1549 private void provide(final String factoryPid, final ConfigurationImpl config) {
1550
1551 final Dictionary rawProperties;
1552 final long revision;
1553 synchronized ( config )
1554 {
1555 rawProperties = config.getProperties( true );
1556 revision = config.getRevision();
1557 }
1558
1559 log( LogService.LOG_DEBUG, "Updating service {0} with configuration {1}/{2}@{3}", new Object[]
1560 { factoryPid, config.getFactoryPid(), config.getPid(), new Long( revision ) } );
1561
1562 // CM 1.4 / 104.13.2.1
1563 final Bundle serviceBundle = this.sr.getBundle();
Felix Meschberger41243192009-01-14 19:59:58 +00001564 if ( serviceBundle == null )
1565 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001566 log(
1567 LogService.LOG_INFO,
1568 "ManagedServiceFactory for factory PID {0} seems to already have been unregistered, not updating with factory",
1569 new Object[]
1570 { factoryPid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001571 return;
1572 }
1573
Felix Meschberger273985f2012-07-05 12:28:06 +00001574 if ( !canReceive( serviceBundle, config.getBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001575 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001576 log( LogService.LOG_ERROR,
1577 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001578 new Object[]
Felix Meschberger273985f2012-07-05 12:28:06 +00001579 { config.getPid(), ConfigurationManager.toString( sr ), config.getBundleLocation() } );
1580
1581 // no service, really, bail out
1582 return;
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001583 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001584
1585 // 104.4.2 Dynamic Binding
1586 config.tryBindLocation( serviceBundle.getLocation() );
1587
1588 // update the service with the configuration (if non-null)
1589 if ( rawProperties != null )
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001590 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001591 log( LogService.LOG_DEBUG, "{0}: Updating configuration pid={1}", new Object[]
1592 { ConfigurationManager.toString( sr ), config.getPid() } );
1593 managedServiceFactoryTracker.provideConfiguration( sr, config.getPid(), config.getFactoryPid(),
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001594 rawProperties, revision, this.configs );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001595 }
1596 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001597
1598
Felix Meschberger432e3872008-03-07 14:58:57 +00001599 public String toString()
1600 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001601 return "ManagedServiceFactory Update: factoryPid=" + Arrays.asList( this.factoryPids );
Felix Meschberger432e3872008-03-07 14:58:57 +00001602 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001603 }
1604
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001605 private abstract class ConfigurationProvider<T> implements Runnable
1606 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001607
1608 protected final ConfigurationImpl config;
1609 protected final long revision;
1610 protected final Dictionary<String, ?> properties;
Felix Meschbergerfffde292012-11-18 18:02:20 +00001611 private BaseTracker<T> helper;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001612
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001613
1614 protected ConfigurationProvider( final ConfigurationImpl config )
1615 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001616 synchronized ( config )
1617 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001618 this.config = config;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001619 this.revision = config.getRevision();
1620 this.properties = config.getProperties( true );
1621 }
1622 }
1623
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001624
1625 protected TargetedPID getTargetedServicePid()
1626 {
1627 final TargetedPID factoryPid = this.config.getFactoryPid();
1628 if ( factoryPid != null )
1629 {
1630 return factoryPid;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001631 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001632 return this.config.getPid();
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001633 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001634
1635
Felix Meschbergerfffde292012-11-18 18:02:20 +00001636 protected BaseTracker<T> getHelper()
1637 {
1638 if ( this.helper == null )
1639 {
1640 this.helper = ( BaseTracker<T> ) ( ( this.config.getFactoryPid() == null ) ? ConfigurationManager.this.managedServiceTracker
1641 : ConfigurationManager.this.managedServiceFactoryTracker );
1642 }
1643 return this.helper;
1644 }
1645
1646
Felix Meschberger273985f2012-07-05 12:28:06 +00001647 protected boolean provideReplacement( ServiceReference<T> sr )
1648 {
1649 if ( this.config.getFactoryPid() == null )
1650 {
1651 try
1652 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001653 final String configPidString = this.getHelper().getServicePid( sr, this.config.getPid() );
Felix Meschberger1ff5c532012-07-08 18:23:08 +00001654 final ConfigurationImpl rc = getTargetedConfiguration( configPidString, sr );
Felix Meschberger273985f2012-07-05 12:28:06 +00001655 if ( rc != null )
1656 {
1657 final TargetedPID configPid;
1658 final Dictionary properties;
1659 final long revision;
Felix Meschbergercd5195f2012-07-05 17:17:45 +00001660 synchronized ( rc )
Felix Meschberger273985f2012-07-05 12:28:06 +00001661 {
Felix Meschbergercd5195f2012-07-05 17:17:45 +00001662 configPid = rc.getPid();
1663 properties = rc.getProperties( true );
1664 revision = rc.getRevision();
Felix Meschberger273985f2012-07-05 12:28:06 +00001665 }
1666
Felix Meschbergerfffde292012-11-18 18:02:20 +00001667 this.getHelper().provideConfiguration( sr, configPid, null, properties, -revision, null );
Felix Meschberger273985f2012-07-05 12:28:06 +00001668
1669 return true;
1670 }
1671 }
1672 catch ( IOException ioe )
1673 {
1674 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1675 { this.config.getPid(), ioe } );
1676 }
1677 catch ( Exception e )
1678 {
1679 log( LogService.LOG_ERROR, "Unexpected problem providing configuration {0} to service {1}",
1680 new Object[]
1681 { this.config.getPid(), ConfigurationManager.toString( sr ), e } );
1682 }
1683 }
1684
1685 // factory or no replacement available
1686 return false;
1687 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001688 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001689
1690 /**
1691 * The <code>UpdateConfiguration</code> is used to update
1692 * <code>ManagedService[Factory]</code> services with the configuration
1693 * they are subscribed to. This may cause the configuration to be
1694 * supplied to multiple services.
1695 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001696 private class UpdateConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001697 {
1698
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001699 UpdateConfiguration( final ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001700 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001701 super( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001702 }
1703
1704
1705 public void run()
1706 {
Felix Meschberger61207232011-11-17 10:06:45 +00001707 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1708 { config.getPid(), new Long( revision ) } );
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001709
Felix Meschbergerfffde292012-11-18 18:02:20 +00001710 final List<ServiceReference<?>> srList = this.getHelper().getServices( getTargetedServicePid() );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001711 if ( !srList.isEmpty() )
Felix Meschberger41cce522009-08-19 05:54:40 +00001712 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001713 // optionally bind dynamically to the first service
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001714 config.tryBindLocation( srList.get( 0 ).getBundle().getLocation() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001715
1716 final String configBundleLocation = config.getBundleLocation();
1717
1718 // provide configuration to all services from the
1719 // correct bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001720 for (ServiceReference<?> ref : srList)
Felix Meschberger41cce522009-08-19 05:54:40 +00001721 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001722 final Bundle refBundle = ref.getBundle();
1723 if ( refBundle == null )
Felix Meschberger41cce522009-08-19 05:54:40 +00001724 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001725 log( LogService.LOG_DEBUG,
1726 "Service {0} seems to be unregistered concurrently (not providing configuration)",
1727 new Object[]
1728 { ConfigurationManager.toString( ref ) } );
1729 }
1730 else if ( canReceive( refBundle, configBundleLocation ) )
1731 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001732 this.getHelper().provideConfiguration( ref, this.config.getPid(), this.config.getFactoryPid(),
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001733 this.properties, this.revision, null );
Felix Meschberger2444da62011-11-17 11:17:50 +00001734 }
1735 else
1736 {
1737 // CM 1.4 / 104.13.2.2
Felix Meschberger4f269292011-10-21 13:52:31 +00001738 log( LogService.LOG_ERROR,
1739 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1740 new Object[]
1741 { config.getPid(), ConfigurationManager.toString( ref ), configBundleLocation } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001742 }
1743
Felix Meschberger41cce522009-08-19 05:54:40 +00001744 }
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001745 }
Felix Meschberger137ee722011-11-16 09:51:59 +00001746 else if ( isLogEnabled( LogService.LOG_DEBUG ) )
1747 {
Felix Meschberger1ee888d2011-11-16 12:42:57 +00001748 log( LogService.LOG_DEBUG, "No ManagedService[Factory] registered for updates to configuration {0}",
Felix Meschberger137ee722011-11-16 09:51:59 +00001749 new Object[]
1750 { config.getPid() } );
1751 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001752 }
1753
1754
Felix Meschberger432e3872008-03-07 14:58:57 +00001755 public String toString()
1756 {
1757 return "Update: pid=" + config.getPid();
1758 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001759 }
1760
Felix Meschberger007c50e2011-10-20 12:39:38 +00001761
1762 /**
1763 * The <code>DeleteConfiguration</code> class is used to inform
1764 * <code>ManagedService[Factory]</code> services of a configuration
1765 * being deleted.
1766 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001767 private class DeleteConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001768 {
Felix Meschberger66423332007-08-22 08:46:34 +00001769
Felix Meschbergerc12db8c2009-08-19 06:43:59 +00001770 private final String configLocation;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001771
1772
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001773 DeleteConfiguration( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001774 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001775 /*
1776 * NOTE: We keep the configuration because it might be cleared just
1777 * after calling this method. The pid and factoryPid fields are
1778 * final and cannot be reset.
1779 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001780 super(config);
Felix Meschberger007c50e2011-10-20 12:39:38 +00001781 this.configLocation = config.getBundleLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001782 }
1783
1784
1785 public void run()
1786 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001787 List<ServiceReference<?>> srList = this.getHelper().getServices( getTargetedServicePid() );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001788 if ( !srList.isEmpty() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001789 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001790 for (ServiceReference<?> sr : srList)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001791 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001792 final Bundle srBundle = sr.getBundle();
1793 if ( srBundle == null )
1794 {
1795 log( LogService.LOG_DEBUG,
1796 "Service {0} seems to be unregistered concurrently (not removing configuration)",
1797 new Object[]
1798 { ConfigurationManager.toString( sr ) } );
1799 }
1800 else if ( canReceive( srBundle, configLocation ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001801 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001802 // revoke configuration unless a replacement
1803 // configuration can be provided
1804 if ( !this.provideReplacement( sr ) )
1805 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001806 this.getHelper().removeConfiguration( sr, this.config.getPid(), this.config.getFactoryPid() );
Felix Meschberger273985f2012-07-05 12:28:06 +00001807 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001808 }
Felix Meschberger2444da62011-11-17 11:17:50 +00001809 else
1810 {
1811 // CM 1.4 / 104.13.2.2
1812 log( LogService.LOG_ERROR,
1813 "Cannot remove configuration {0} for {1}: No visibility to configuration bound to {2}",
1814 new Object[]
1815 { config.getPid(), ConfigurationManager.toString( sr ), configLocation } );
1816 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001817 }
1818 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001819
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001820 final TargetedPID factoryPid = config.getFactoryPid();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001821 if ( factoryPid != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001822 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001823 // remove the pid from the factory
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001824 final String pid = config.getPidString();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001825 try
1826 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001827 Factory factory = getOrCreateFactory( factoryPid.toString() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001828 factory.removePID( pid );
1829 factory.store();
1830 }
1831 catch ( IOException ioe )
1832 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001833 log( LogService.LOG_ERROR, "Failed removing {0} from the factory {1}", new Object[]
1834 { pid, factoryPid, ioe } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001835 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001836 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001837 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001838
Felix Meschberger432e3872008-03-07 14:58:57 +00001839 public String toString()
1840 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001841 return "Delete: pid=" + config.getPid();
Felix Meschberger432e3872008-03-07 14:58:57 +00001842 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001843 }
1844
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001845 private class LocationChanged extends ConfigurationProvider
Felix Meschberger007c50e2011-10-20 12:39:38 +00001846 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001847 private final String oldLocation;
1848
1849
1850 LocationChanged( ConfigurationImpl config, String oldLocation )
1851 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001852 super( config );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001853 this.oldLocation = oldLocation;
1854 }
1855
1856
1857 public void run()
1858 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001859 List<ServiceReference<?>> srList = this.getHelper().getServices( getTargetedServicePid() );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001860 if ( !srList.isEmpty() )
Felix Meschberger007c50e2011-10-20 12:39:38 +00001861 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001862 for (final ServiceReference<?> sr : srList)
Felix Meschberger007c50e2011-10-20 12:39:38 +00001863 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001864 final Bundle srBundle = sr.getBundle();
1865 if ( srBundle == null )
1866 {
1867 log( LogService.LOG_DEBUG,
1868 "Service {0} seems to be unregistered concurrently (not processing)", new Object[]
1869 { ConfigurationManager.toString( sr ) } );
1870 continue;
1871 }
1872
1873 final boolean wasVisible = canReceive( srBundle, oldLocation );
1874 final boolean isVisible = canReceive( srBundle, config.getBundleLocation() );
1875
1876 // make sure the config is dynamically bound to the first
1877 // service if the config has been unbound causing this update
1878 if ( isVisible )
1879 {
1880 config.tryBindLocation( srBundle.getLocation() );
1881 }
1882
Felix Meschberger007c50e2011-10-20 12:39:38 +00001883 if ( wasVisible && !isVisible )
1884 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001885 // revoke configuration unless a replacement
1886 // configuration can be provided
1887 if ( !this.provideReplacement( sr ) )
1888 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001889 this.getHelper().removeConfiguration( sr, this.config.getPid(), this.config.getFactoryPid() );
Felix Meschberger273985f2012-07-05 12:28:06 +00001890 log( LogService.LOG_DEBUG, "Configuration {0} revoked from {1} (no more visibility)",
1891 new Object[]
1892 { config.getPid(), ConfigurationManager.toString( sr ) } );
1893 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001894 }
1895 else if ( !wasVisible && isVisible )
1896 {
1897 // call updated method
Felix Meschbergerfffde292012-11-18 18:02:20 +00001898 this.getHelper().provideConfiguration( sr, this.config.getPid(), this.config.getFactoryPid(),
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001899 this.properties, this.revision, null );
Felix Meschberger4f269292011-10-21 13:52:31 +00001900 log( LogService.LOG_DEBUG, "Configuration {0} provided to {1} (new visibility)", new Object[]
1901 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger35658d52011-10-20 21:43:58 +00001902 }
Felix Meschberger4f269292011-10-21 13:52:31 +00001903 else
Felix Meschberger35658d52011-10-20 21:43:58 +00001904 {
1905 // same visibility as before
Felix Meschberger4f269292011-10-21 13:52:31 +00001906 log( LogService.LOG_DEBUG, "Unmodified visibility to configuration {0} for {1}", new Object[]
1907 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001908 }
1909 }
1910 }
1911 }
1912
1913
1914 public String toString()
1915 {
1916 return "Location Changed (pid=" + config.getPid() + "): " + oldLocation + " ==> "
1917 + config.getBundleLocation();
1918 }
1919 }
1920
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001921 private class FireConfigurationEvent implements Runnable
1922 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001923 private final int type;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001924
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001925 private final String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001926
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001927 private final String factoryPid;
1928
1929 private final ServiceReference[] listenerReferences;
1930
1931 private final ConfigurationListener[] listeners;
1932
1933 private final Bundle[] listenerProvider;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001934
Felix Meschberger0770cad2012-06-11 12:36:52 +00001935 private ConfigurationEvent event;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001936
Felix Meschbergere94b1572012-07-14 11:59:29 +00001937 private FireConfigurationEvent( final ServiceTracker listenerTracker, final int type, final String pid, final String factoryPid)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001938 {
1939 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001940 this.pid = pid;
1941 this.factoryPid = factoryPid;
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001942
Felix Meschbergere94b1572012-07-14 11:59:29 +00001943 final ServiceReference[] srs = listenerTracker.getServiceReferences();
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001944 if ( srs == null || srs.length == 0 )
1945 {
1946 this.listenerReferences = null;
1947 this.listeners = null;
1948 this.listenerProvider = null;
1949 }
1950 else
1951 {
1952 this.listenerReferences = srs;
1953 this.listeners = new ConfigurationListener[srs.length];
1954 this.listenerProvider = new Bundle[srs.length];
1955 for ( int i = 0; i < srs.length; i++ )
1956 {
Felix Meschbergere94b1572012-07-14 11:59:29 +00001957 this.listeners[i] = ( ConfigurationListener ) listenerTracker.getService( srs[i] );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001958 this.listenerProvider[i] = srs[i].getBundle();
1959 }
1960 }
1961 }
1962
1963
1964 boolean hasConfigurationEventListeners()
1965 {
1966 return this.listenerReferences != null;
1967 }
1968
1969
1970 String getTypeName()
1971 {
1972 switch ( type )
1973 {
1974 case ConfigurationEvent.CM_DELETED:
1975 return "CM_DELETED";
1976 case ConfigurationEvent.CM_UPDATED:
1977 return "CM_UPDATED";
Felix Meschberger007c50e2011-10-20 12:39:38 +00001978 case ConfigurationEvent.CM_LOCATION_CHANGED:
1979 return "CM_LOCATION_CHANGED";
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001980 default:
1981 return "<UNKNOWN(" + type + ")>";
1982 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001983 }
1984
1985
1986 public void run()
1987 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001988 for ( int i = 0; i < listeners.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001989 {
Felix Meschberger0770cad2012-06-11 12:36:52 +00001990 sendEvent( i );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001991 }
1992 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001993
Felix Meschberger0770cad2012-06-11 12:36:52 +00001994
Felix Meschberger432e3872008-03-07 14:58:57 +00001995 public String toString()
1996 {
1997 return "Fire ConfigurationEvent: pid=" + pid;
1998 }
Felix Meschberger0770cad2012-06-11 12:36:52 +00001999
2000
2001 private ConfigurationEvent getConfigurationEvent()
2002 {
2003 if ( event == null )
2004 {
2005 this.event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
2006 }
2007 return event;
2008 }
2009
2010
2011 private void sendEvent( final int serviceIndex )
2012 {
2013 if ( listenerProvider[serviceIndex].getState() == Bundle.ACTIVE && this.listeners[serviceIndex] != null )
2014 {
2015 log( LogService.LOG_DEBUG, "Sending {0} event for {1} to {2}", new Object[]
2016 { getTypeName(), pid, ConfigurationManager.toString( listenerReferences[serviceIndex] ) } );
2017
2018 try
2019 {
2020 listeners[serviceIndex].configurationEvent( getConfigurationEvent() );
2021 }
2022 catch ( Throwable t )
2023 {
2024 log( LogService.LOG_ERROR, "Unexpected problem delivering configuration event to {0}", new Object[]
2025 { ConfigurationManager.toString( listenerReferences[serviceIndex] ), t } );
2026 }
2027 finally
2028 {
2029 this.listeners[serviceIndex] = null;
2030 }
2031 }
2032 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002033 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002034}
Felix Meschberger273985f2012-07-05 12:28:06 +00002035