blob: c1b80a543fdc8d143651e75f45528bed981155aa [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;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000049import org.osgi.framework.InvalidSyntaxException;
50import org.osgi.framework.ServiceReference;
51import org.osgi.framework.ServiceRegistration;
52import org.osgi.service.cm.ConfigurationAdmin;
53import org.osgi.service.cm.ConfigurationEvent;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000054import org.osgi.service.cm.ConfigurationListener;
55import org.osgi.service.cm.ConfigurationPermission;
56import org.osgi.service.cm.ConfigurationPlugin;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000057import org.osgi.service.cm.SynchronousConfigurationListener;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000058import org.osgi.service.log.LogService;
59import org.osgi.util.tracker.ServiceTracker;
60
61
62/**
63 * The <code>ConfigurationManager</code> is the central class in this
64 * implementation of the Configuration Admin Service Specification. As such it
65 * has the following tasks:
66 * <ul>
67 * <li>It is a <code>BundleActivator</code> which is called when the bundle
68 * is started and stopped.
69 * <li>It is a <code>BundleListener</code> which gets informed when the
70 * states of bundles change. Mostly this is needed to unbind any bound
71 * configuration in case a bundle is uninstalled.
72 * <li>It is a <code>ServiceListener</code> which gets informed when
73 * <code>ManagedService</code> and <code>ManagedServiceFactory</code>
74 * services are registered and unregistered. This is used to provide
75 * configuration to these services. As a service listener it also listens for
76 * {@link PersistenceManager} instances being registered to support different
77 * configuration persistence layers.
78 * <li>A {@link ConfigurationAdminFactory} instance is registered as the
79 * <code>ConfigurationAdmin</code> service.
80 * <li>A {@link FilePersistenceManager} instance is registered as a default
81 * {@link PersistenceManager}.
82 * <li>Last but not least this instance manages all tasks laid out in the
83 * specification such as maintaining configuration, taking care of configuration
84 * events, etc.
85 * </ul>
86 * <p>
87 * The default {@link FilePersistenceManager} is configured with a configuration
88 * location taken from the <code>felix.cm.dir</code> framework property. If
89 * this property is not set the <code>config</code> directory in the current
90 * working directory as specified in the <code>user.dir</code> system property
91 * is used.
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000092 */
93public class ConfigurationManager implements BundleActivator, BundleListener
94{
95
96 /**
97 * The name of the bundle context property defining the location for the
98 * configuration files (value is "felix.cm.dir").
Felix Meschberger2fd5b582007-12-10 10:32:29 +000099 *
Carsten Ziegeler7853b9a2008-01-11 16:30:24 +0000100 * @see #start(BundleContext)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000101 */
102 public static final String CM_CONFIG_DIR = "felix.cm.dir";
103
Felix Meschberger08282c32009-01-28 07:01:55 +0000104 /**
105 * The name of the bundle context property defining the maximum log level
106 * (value is "felix.cm.loglevel"). The log level setting is only used if
107 * there is no OSGi LogService available. Otherwise this setting is ignored.
108 * <p>
109 * This value of this property is expected to be an integer number
110 * corresponding to the log level values of the OSGi LogService. That is 1
111 * for errors, 2 for warnings, 3 for informational messages and 4 for debug
112 * messages. The default value is 2, such that only warnings and errors are
113 * logged in the absence of a LogService.
114 */
115 public static final String CM_LOG_LEVEL = "felix.cm.loglevel";
116
Felix Meschberger85b355d2007-08-31 07:17:38 +0000117 // The name of the LogService (not using the class, which might be missing)
118 private static final String LOG_SERVICE_NAME = "org.osgi.service.log.LogService";
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000119
Felix Meschberger08282c32009-01-28 07:01:55 +0000120 private static final int CM_LOG_LEVEL_DEFAULT = 2;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000121
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000122 // random number generator to create configuration PIDs for factory
123 // configurations
Felix Meschberger417f66c2011-02-04 11:25:23 +0000124 private static Random numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000125
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000126 // the BundleContext of the Configuration Admin Service bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000127 BundleContext bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000128
Felix Meschberger99630732012-12-14 10:24:10 +0000129 // the service registration of the default file persistence manager
130 private volatile ServiceRegistration filepmRegistration;
131
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000132 // the service registration of the configuration admin
Felix Meschberger4b26df92011-02-01 12:41:45 +0000133 private volatile ServiceRegistration configurationAdminRegistration;
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000134
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000135 // the ServiceTracker to emit log services (see log(int, String, Throwable))
136 private ServiceTracker logTracker;
137
138 // the ConfigurationEvent listeners
139 private ServiceTracker configurationListenerTracker;
140
Felix Meschbergere94b1572012-07-14 11:59:29 +0000141 // the synchronous ConfigurationEvent listeners
142 private ServiceTracker syncConfigurationListenerTracker;
143
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000144 // service tracker for managed services
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000145 private ManagedServiceTracker managedServiceTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000146
147 // service tracker for managed service factories
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000148 private ManagedServiceFactoryTracker managedServiceFactoryTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000149
150 // PersistenceManager services
151 private ServiceTracker persistenceManagerTracker;
152
153 // the thread used to schedule tasks required to run asynchronously
154 private UpdateThread updateThread;
155
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000156 // the thread used to schedule events to be dispatched asynchronously
157 private UpdateThread eventThread;
158
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000159 /**
160 * The actual list of {@link PersistenceManager persistence managers} to use
161 * when looking for configuration data. This list is built from the
162 * {@link #persistenceManagerMap}, which is ordered according to the
163 * {@link RankingComparator}.
164 */
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000165 private CachingPersistenceManagerProxy[] persistenceManagers;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000166
167 // the persistenceManagerTracker.getTrackingCount when the
168 // persistenceManagers were last got
169 private int pmtCount;
170
171 // the cache of Factory instances mapped by their factory PID
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000172 private final HashMap<String, Factory> factories = new HashMap<String, Factory>();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000173
174 // the cache of Configuration instances mapped by their PID
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000175 // have this always set to prevent NPE on bundle shutdown
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000176 private final HashMap<String, ConfigurationImpl> configurations = new HashMap<String, ConfigurationImpl>();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000177
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000178 /**
179 * The map of dynamic configuration bindings. This maps the
180 * PID of the dynamically bound configuration or factory to its bundle
181 * location.
182 * <p>
183 * On bundle startup this map is loaded from persistence and validated
184 * against the locations of installed bundles: Entries pointing to bundle
185 * locations not currently installed are removed.
186 * <p>
187 * The map is written to persistence on each change.
188 */
189 private DynamicBindings dynamicBindings;
190
Felix Meschberger08282c32009-01-28 07:01:55 +0000191 // the maximum log level when no LogService is available
192 private int logLevel = CM_LOG_LEVEL_DEFAULT;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000193
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000194 // flag indicating whether BundleChange events should be consumed (FELIX-979)
195 private volatile boolean handleBundleEvents;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000196
Felix Meschberger623f7142012-01-31 07:13:37 +0000197 // flag indicating whether the manager is considered alive
198 private volatile boolean isActive;
199
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000200 public void start( BundleContext bundleContext )
201 {
202 // track the log service using a ServiceTracker
Felix Meschberger85b355d2007-08-31 07:17:38 +0000203 logTracker = new ServiceTracker( bundleContext, LOG_SERVICE_NAME , null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000204 logTracker.open();
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000205
Felix Meschberger08282c32009-01-28 07:01:55 +0000206 // assign the log level
207 String logLevelProp = bundleContext.getProperty( CM_LOG_LEVEL );
208 if ( logLevelProp == null )
209 {
210 logLevel = CM_LOG_LEVEL_DEFAULT;
211 }
212 else
213 {
214 try
215 {
216 logLevel = Integer.parseInt( logLevelProp );
217 }
218 catch ( NumberFormatException nfe )
219 {
220 logLevel = CM_LOG_LEVEL_DEFAULT;
221 }
222 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000223
224 // set up some fields
225 this.bundleContext = bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000226
227 // configurationlistener support
228 configurationListenerTracker = new ServiceTracker( bundleContext, ConfigurationListener.class.getName(), null );
229 configurationListenerTracker.open();
Felix Meschbergere94b1572012-07-14 11:59:29 +0000230 syncConfigurationListenerTracker = new ServiceTracker( bundleContext,
231 SynchronousConfigurationListener.class.getName(), null );
232 syncConfigurationListenerTracker.open();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000233
234 // initialize the asynchonous updater thread
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000235 ThreadGroup tg = new ThreadGroup( "Configuration Admin Service" );
236 tg.setDaemon( true );
237 this.updateThread = new UpdateThread( this, tg, "CM Configuration Updater" );
238 this.eventThread = new UpdateThread( this, tg, "CM Event Dispatcher" );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000239
240 // set up the location (might throw IllegalArgumentException)
241 try
242 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000243 FilePersistenceManager fpm = new FilePersistenceManager( bundleContext, bundleContext
244 .getProperty( CM_CONFIG_DIR ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000245 Hashtable props = new Hashtable();
246 props.put( Constants.SERVICE_PID, fpm.getClass().getName() );
247 props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
248 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
249 props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
Felix Meschberger99630732012-12-14 10:24:10 +0000250 filepmRegistration = bundleContext.registerService( PersistenceManager.class.getName(), fpm, props );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000251
252 // setup dynamic configuration bindings
253 dynamicBindings = new DynamicBindings( bundleContext, fpm );
254 }
255 catch ( IOException ioe )
256 {
257 log( LogService.LOG_ERROR, "Failure setting up dynamic configuration bindings", ioe );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000258 }
259 catch ( IllegalArgumentException iae )
260 {
261 log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
262 }
263
264 // register as bundle and service listener
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000265 handleBundleEvents = true;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000266 bundleContext.addBundleListener( this );
267
268 // get all persistence managers to begin with
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000269 pmtCount = 1; // make sure to get the persistence managers at least once
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000270 persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
271 persistenceManagerTracker.open();
272
Felix Meschberger623f7142012-01-31 07:13:37 +0000273 // consider alive now (before clients use Configuration Admin
274 // service registered in the next step)
275 isActive = true;
276
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000277 // create and register configuration admin - start after PM tracker ...
278 ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
279 Hashtable props = new Hashtable();
280 props.put( Constants.SERVICE_PID, "org.apache.felix.cm.ConfigurationAdmin" );
281 props.put( Constants.SERVICE_DESCRIPTION, "Configuration Admin Service Specification 1.2 Implementation" );
282 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000283 configurationAdminRegistration = bundleContext.registerService( ConfigurationAdmin.class.getName(), caf, props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000284
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000285 // start handling ManagedService[Factory] services
286 managedServiceTracker = new ManagedServiceTracker(this);
287 managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this);
288
Felix Meschberger4b26df92011-02-01 12:41:45 +0000289 // start processing the event queues only after registering the service
290 // see FELIX-2813 for details
291 this.updateThread.start();
292 this.eventThread.start();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000293 }
294
295
296 public void stop( BundleContext bundleContext )
297 {
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000298
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000299 // stop handling bundle events immediately
300 handleBundleEvents = false;
301
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000302 // stop handling ManagedService[Factory] services
303 managedServiceFactoryTracker.close();
304 managedServiceTracker.close();
305
Felix Meschberger4b26df92011-02-01 12:41:45 +0000306 // stop queue processing before unregistering the service
307 // see FELIX-2813 for details
308 if ( updateThread != null )
309 {
310 updateThread.terminate();
311 }
312 if ( eventThread != null )
313 {
314 eventThread.terminate();
315 }
316
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000317 // immediately unregister the Configuration Admin before cleaning up
Felix Meschberger10568352009-01-15 08:57:11 +0000318 // clearing the field before actually unregistering the service
319 // prevents IllegalStateException in getServiceReference() if
320 // the field is not null but the service already unregistered
Felix Meschberger99630732012-12-14 10:24:10 +0000321 final ServiceRegistration caReg = configurationAdminRegistration;
322 configurationAdminRegistration = null;
323 if ( caReg != null )
324 {
325 caReg.unregister();
Felix Meschberger10568352009-01-15 08:57:11 +0000326 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000327
Felix Meschberger623f7142012-01-31 07:13:37 +0000328 // consider inactive after unregistering such that during
329 // unregistration the manager is still alive and can react
330 isActive = false;
331
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000332 // don't care for PersistenceManagers any more
333 persistenceManagerTracker.close();
334
Felix Meschberger99630732012-12-14 10:24:10 +0000335 // shutdown the file persistence manager
336 final ServiceRegistration filePmReg = filepmRegistration;
337 filepmRegistration = null;
338 if ( filePmReg != null )
339 {
340 filePmReg.unregister();
341 }
342
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000343 // stop listening for events
344 bundleContext.removeBundleListener( this );
345
346 if ( configurationListenerTracker != null )
347 {
348 configurationListenerTracker.close();
349 }
350
Felix Meschbergere94b1572012-07-14 11:59:29 +0000351 if ( syncConfigurationListenerTracker != null )
352 {
353 syncConfigurationListenerTracker.close();
354 }
355
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000356 if ( logTracker != null )
357 {
358 logTracker.close();
359 }
360
Felix Meschberger6a698df2009-08-16 18:38:46 +0000361 // just ensure the configuration cache is empty
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000362 synchronized ( configurations )
363 {
364 configurations.clear();
365 }
366
Felix Meschberger6a698df2009-08-16 18:38:46 +0000367 // just ensure the factory cache is empty
368 synchronized ( factories )
369 {
370 factories.clear();
371 }
372
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000373 this.bundleContext = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000374 }
375
376
Felix Meschberger623f7142012-01-31 07:13:37 +0000377 /**
378 * Returns <code>true</code> if this manager is considered active.
379 */
380 boolean isActive()
381 {
382 return isActive;
383 }
384
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000385 public BundleContext getBundleContext()
386 {
387 return bundleContext;
388 }
Felix Meschberger623f7142012-01-31 07:13:37 +0000389
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000390 // ---------- Configuration caching support --------------------------------
391
392 ConfigurationImpl getCachedConfiguration( String pid )
393 {
394 synchronized ( configurations )
395 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000396 return configurations.get( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000397 }
398 }
399
400
Felix Meschberger6a698df2009-08-16 18:38:46 +0000401 ConfigurationImpl[] getCachedConfigurations()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000402 {
403 synchronized ( configurations )
404 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000405 return configurations.values().toArray(
Felix Meschberger6a698df2009-08-16 18:38:46 +0000406 new ConfigurationImpl[configurations.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000407 }
408 }
409
410
Felix Meschberger2941ef92007-08-20 13:15:16 +0000411 ConfigurationImpl cacheConfiguration( ConfigurationImpl configuration )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000412 {
413 synchronized ( configurations )
414 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000415 final String pid = configuration.getPidString();
416 final Object existing = configurations.get( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000417 if ( existing != null )
418 {
419 return ( ConfigurationImpl ) existing;
420 }
421
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000422 configurations.put( pid, configuration );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000423 return configuration;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000424 }
425 }
426
427
428 void removeConfiguration( ConfigurationImpl configuration )
429 {
430 synchronized ( configurations )
431 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000432 configurations.remove( configuration.getPidString() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000433 }
434 }
435
436
Felix Meschberger6a698df2009-08-16 18:38:46 +0000437 Factory getCachedFactory( String factoryPid )
438 {
439 synchronized ( factories )
440 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000441 return factories.get( factoryPid );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000442 }
443 }
444
445
446 Factory[] getCachedFactories()
447 {
448 synchronized ( factories )
449 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000450 return factories.values().toArray( new Factory[factories.size()] );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000451 }
452 }
453
454
455 void cacheFactory( Factory factory )
456 {
457 synchronized ( factories )
458 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000459 factories.put( factory.getFactoryPidString(), factory );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000460 }
461 }
462
463
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000464 // ---------- ConfigurationAdminImpl support
Felix Meschberger6a698df2009-08-16 18:38:46 +0000465
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000466 void setDynamicBundleLocation( final String pid, final String location )
467 {
468 if ( dynamicBindings != null )
469 {
470 try
471 {
472 dynamicBindings.putLocation( pid, location );
473 }
474 catch ( IOException ioe )
475 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000476 log( LogService.LOG_ERROR, "Failed storing dynamic configuration binding for {0} to {1}", new Object[]
477 { pid, location, ioe } );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000478 }
479 }
480 }
481
482
483 String getDynamicBundleLocation( final String pid )
484 {
485 if ( dynamicBindings != null )
486 {
487 return dynamicBindings.getLocation( pid );
488 }
489
490 return null;
491 }
492
493
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000494 ConfigurationImpl createFactoryConfiguration( String factoryPid, String location ) throws IOException
495 {
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000496 return cacheConfiguration( createConfiguration( createPid( factoryPid ), factoryPid, location ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000497 }
498
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000499 /**
500 * Returns a targeted configuration for the given service PID and
501 * the reference target service.
Felix Meschberger273985f2012-07-05 12:28:06 +0000502 * <p>
503 * A configuration returned has already been checked for visibility
504 * by the bundle registering the referenced service. Additionally,
505 * the configuration is also dynamically bound if needed.
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000506 *
507 * @param rawPid The raw service PID to get targeted configuration for.
508 * @param target The target <code>ServiceReference</code> to get
509 * configuration for.
510 * @return The best matching targeted configuration or <code>null</code>
511 * if there is no configuration at all.
512 * @throwss IOException if an error occurrs reading configurations
513 * from persistence.
514 */
515 ConfigurationImpl getTargetedConfiguration( final String rawPid, final ServiceReference target ) throws IOException
516 {
517 final Bundle serviceBundle = target.getBundle();
518 if ( serviceBundle != null )
519 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000520 // list of targeted PIDs to check
521 // (StringBuffer for pre-1.5 API compatibility)
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000522 final StringBuffer targetedPid = new StringBuffer( rawPid );
523 int i = 3;
524 String[] names = new String[4];
525 names[i--] = targetedPid.toString();
526 targetedPid.append( '|' ).append( serviceBundle.getSymbolicName() );
527 names[i--] = targetedPid.toString();
528 targetedPid.append( '|' ).append( TargetedPID.getBundleVersion( serviceBundle ) );
529 names[i--] = targetedPid.toString();
530 targetedPid.append( '|' ).append( serviceBundle.getLocation() );
531 names[i--] = targetedPid.toString();
532
533 for ( String candidate : names )
534 {
535 ConfigurationImpl config = getConfiguration( candidate );
Felix Meschbergercd5195f2012-07-05 17:17:45 +0000536 if ( config != null && !config.isDeleted() )
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000537 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000538 // check visibility to use and dynamically bind
539 if ( canReceive( serviceBundle, config.getBundleLocation() ) )
540 {
541 config.tryBindLocation( serviceBundle.getLocation() );
542 return config;
543 }
544
545 // CM 1.4 / 104.13.2.2 / 104.5.3
546 // act as if there is no configuration
547 log(
548 LogService.LOG_DEBUG,
549 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}; calling with null",
550 new Object[]
551 { config.getPid(), toString( target ), config.getBundleLocation() } );
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000552 }
553 }
554 }
Felix Meschberger273985f2012-07-05 12:28:06 +0000555 else
556 {
557 log( LogService.LOG_INFO,
558 "Service for PID {0} seems to already have been unregistered, not updating with configuration",
559 new Object[]
560 { rawPid } );
561 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000562
563 // service already unregistered, nothing to do really
564 return null;
565 }
566
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000567
Felix Meschbergerad949872011-11-16 10:34:54 +0000568 /**
569 * Returns the {@link ConfigurationImpl} with the given PID if
570 * available in the internal cache or from any persistence manager.
571 * Otherwise <code>null</code> is returned.
572 *
573 * @param pid The PID for which to return the configuration
574 * @return The configuration or <code>null</code> if non exists
575 * @throws IOException If an error occurrs reading from a persistence
576 * manager.
577 */
578 ConfigurationImpl getConfiguration( String pid ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000579 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000580 ConfigurationImpl config = getCachedConfiguration( pid );
581 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000582 {
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000583 log( LogService.LOG_DEBUG, "Found cached configuration {0} bound to {1}", new Object[]
584 { pid, config.getBundleLocation() } );
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000585
586 config.ensureFactoryConfigPersisted();
587
Felix Meschberger2941ef92007-08-20 13:15:16 +0000588 return config;
589 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000590
Felix Meschberger2941ef92007-08-20 13:15:16 +0000591 PersistenceManager[] pmList = getPersistenceManagers();
592 for ( int i = 0; i < pmList.length; i++ )
593 {
594 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000595 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000596 Dictionary props = pmList[i].load( pid );
597 config = new ConfigurationImpl( this, pmList[i], props );
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000598 log( LogService.LOG_DEBUG, "Found existing configuration {0} bound to {1}", new Object[]
599 { pid, config.getBundleLocation() } );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000600 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000601 }
602 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000603
Felix Meschberger2941ef92007-08-20 13:15:16 +0000604 // neither the cache nor any persistence manager has configuration
605 return null;
606 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000607
608
Felix Meschbergerad949872011-11-16 10:34:54 +0000609 /**
610 * Creates a regular (non-factory) configuration for the given PID
611 * setting the bundle location accordingly.
612 * <p>
613 * This method assumes the configuration to not exist yet and will
614 * create it without further checking.
615 *
616 * @param pid The PID of the new configuration
617 * @param bundleLocation The location to set on the new configuration.
618 * This may be <code>null</code> to not bind the configuration
619 * yet.
620 * @return The new configuration persisted in the first persistence
621 * manager.
622 * @throws IOException If an error occurrs writing the configuration
623 * to the persistence.
624 */
625 ConfigurationImpl createConfiguration( String pid, String bundleLocation ) throws IOException
Felix Meschberger2941ef92007-08-20 13:15:16 +0000626 {
627 // check for existing (cached or persistent) configuration
Felix Meschbergerad949872011-11-16 10:34:54 +0000628 ConfigurationImpl config = getConfiguration( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000629 if ( config != null )
630 {
631 return config;
632 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000633
Felix Meschberger2941ef92007-08-20 13:15:16 +0000634 // else create new configuration also setting the bundle location
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000635 // and cache the new configuration
636 config = createConfiguration( pid, null, bundleLocation );
637 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000638 }
639
640
641 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
642 throws IOException, InvalidSyntaxException
643 {
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000644 SimpleFilter filter = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000645 if ( filterString != null )
646 {
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000647 filter = SimpleFilter.parse( filterString );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000648 }
649
Felix Meschberger4f269292011-10-21 13:52:31 +0000650 log( LogService.LOG_DEBUG, "Listing configurations matching {0}", new Object[]
651 { filterString } );
652
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000653 List configList = new ArrayList();
654
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000655 CachingPersistenceManagerProxy[] pmList = getPersistenceManagers();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000656 for ( int i = 0; i < pmList.length; i++ )
657 {
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000658 Enumeration configs = pmList[i].getDictionaries( filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000659 while ( configs.hasMoreElements() )
660 {
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000661 final Dictionary config = ( Dictionary ) configs.nextElement();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000662
663 // ignore non-Configuration dictionaries
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000664 final String pid = ( String ) config.get( Constants.SERVICE_PID );
Felix Meschberger86a0d172007-07-04 07:15:01 +0000665 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000666 {
667 continue;
668 }
669
Felix Meschberger007c50e2011-10-20 12:39:38 +0000670 // CM 1.4 / 104.13.2.3 Permission required
Felix Meschberger274aa242012-12-31 19:46:31 +0000671 if ( !configurationAdmin.hasPermission( this,
672 ( String ) config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000673 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000674 log(
675 LogService.LOG_DEBUG,
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000676 "Omitting configuration {0}: No permission for bundle {1} on configuration bound to {2}",
Felix Meschberger4f269292011-10-21 13:52:31 +0000677 new Object[]
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000678 { pid, configurationAdmin.getBundle().getLocation(),
Felix Meschberger4f269292011-10-21 13:52:31 +0000679 config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000680 continue;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000681 }
682
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000683 // ensure the service.pid and returned a cached config if available
684 ConfigurationImpl cfg = getCachedConfiguration( pid );
685 if ( cfg == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000686 {
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000687 cfg = new ConfigurationImpl( this, pmList[i], config );
688 }
Felix Meschberger86a0d172007-07-04 07:15:01 +0000689
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000690 // FELIX-611: Ignore configuration objects without props
691 if ( !cfg.isNew() )
692 {
693 log( LogService.LOG_DEBUG, "Adding configuration {0}", new Object[]
694 { pid } );
695 configList.add( cfg );
696 }
697 else
698 {
699 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Is new", new Object[]
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000700 { pid } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000701 }
702 }
703 }
704
Felix Meschberger8faceff2007-07-04 07:19:48 +0000705 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000706 .size()] );
707 }
708
709
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000710 void deleted( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000711 {
712 // remove the configuration from the cache
713 removeConfiguration( config );
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000714 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000715 updateThread.schedule( new DeleteConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000716 log( LogService.LOG_DEBUG, "DeleteConfiguration({0}) scheduled", new Object[]
717 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000718 }
719
720
Felix Meschbergerce67d732009-08-20 06:26:35 +0000721 void updated( ConfigurationImpl config, boolean fireEvent )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000722 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000723 if ( fireEvent )
724 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000725 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000726 }
727 updateThread.schedule( new UpdateConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000728 log( LogService.LOG_DEBUG, "UpdateConfiguration({0}) scheduled", new Object[]
729 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000730 }
731
732
Felix Meschberger007c50e2011-10-20 12:39:38 +0000733 void locationChanged( ConfigurationImpl config, String oldLocation )
734 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000735 fireConfigurationEvent( ConfigurationEvent.CM_LOCATION_CHANGED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger35658d52011-10-20 21:43:58 +0000736 if ( oldLocation != null && !config.isNew() )
Felix Meschberger007c50e2011-10-20 12:39:38 +0000737 {
738 updateThread.schedule( new LocationChanged( config, oldLocation ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000739 log( LogService.LOG_DEBUG, "LocationChanged({0}, {1}=>{2}) scheduled", new Object[]
740 { config.getPid(), oldLocation, config.getBundleLocation() } );
Felix Meschberger35658d52011-10-20 21:43:58 +0000741 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000742 else
Felix Meschberger35658d52011-10-20 21:43:58 +0000743 {
744 log( LogService.LOG_DEBUG,
Felix Meschberger4f269292011-10-21 13:52:31 +0000745 "LocationChanged not scheduled for {0} (old location is null or configuration is new)", new Object[]
746 { config.getPid() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000747 }
748 }
749
750
Felix Meschberger66423332007-08-22 08:46:34 +0000751 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000752 {
Felix Meschbergere94b1572012-07-14 11:59:29 +0000753 // prevent event senders
754 FireConfigurationEvent asyncSender = new FireConfigurationEvent( this.configurationListenerTracker, type, pid,
755 factoryPid );
756 FireConfigurationEvent syncSender = new FireConfigurationEvent( this.syncConfigurationListenerTracker, type,
757 pid, factoryPid );
758
759 // send synchronous events
760 if ( syncSender.hasConfigurationEventListeners() )
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000761 {
Felix Meschbergere94b1572012-07-14 11:59:29 +0000762 syncSender.run();
763 }
764 else
765 {
766 log( LogService.LOG_DEBUG, "No SynchronousConfigurationListeners to send {0} event to.", new Object[]
767 { syncSender.getTypeName() } );
768 }
769
770 // schedule asynchronous events
771 if ( asyncSender.hasConfigurationEventListeners() )
772 {
773 eventThread.schedule( asyncSender );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000774 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000775 else
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000776 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000777 log( LogService.LOG_DEBUG, "No ConfigurationListeners to send {0} event to.", new Object[]
Felix Meschbergere94b1572012-07-14 11:59:29 +0000778 { asyncSender.getTypeName() } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000779 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000780 }
781
782
783 // ---------- BundleListener -----------------------------------------------
784
785 public void bundleChanged( BundleEvent event )
786 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000787 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000788 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000789 final String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000790
Felix Meschberger6a698df2009-08-16 18:38:46 +0000791 // we only reset dynamic bindings, which are only present in
792 // cached configurations, hence only consider cached configs here
793 final ConfigurationImpl[] configs = getCachedConfigurations();
794 for ( int i = 0; i < configs.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000795 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000796 final ConfigurationImpl cfg = configs[i];
Felix Meschberger41cce522009-08-19 05:54:40 +0000797 if ( location.equals( cfg.getDynamicBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000798 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000799 cfg.setDynamicBundleLocation( null, true );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000800 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000801 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000802 }
803 }
804
805
806 // ---------- internal -----------------------------------------------------
807
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000808 private CachingPersistenceManagerProxy[] getPersistenceManagers()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000809 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000810 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
811 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000812 {
813
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000814 List pmList = new ArrayList();
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000815 CachingPersistenceManagerProxy[] pm;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000816
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000817 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
818 if ( refs == null || refs.length == 0 )
819 {
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000820 pm = new CachingPersistenceManagerProxy[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000821 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000822 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000823 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000824 // sort the references according to the cmRanking property
Felix Meschberger007c50e2011-10-20 12:39:38 +0000825 if ( refs.length > 1 )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000826 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000827 Arrays.sort( refs, RankingComparator.SRV_RANKING );
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000828 }
829
830 // create the service array from the sorted set of referenecs
Felix Meschberger007c50e2011-10-20 12:39:38 +0000831 for ( int i = 0; i < refs.length; i++ )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000832 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000833 Object service = persistenceManagerTracker.getService( refs[i] );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000834 if ( service != null )
835 {
Felix Meschbergera86cdfc2010-08-25 09:32:36 +0000836 pmList.add( new CachingPersistenceManagerProxy( ( PersistenceManager ) service ) );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000837 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000838 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000839
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000840 pm = ( CachingPersistenceManagerProxy[] ) pmList.toArray( new CachingPersistenceManagerProxy[pmList.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000841 }
842
Felix Meschbergerf748bfb2013-09-25 13:54:40 +0000843 pmtCount = currentPmtCount;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000844 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000845 }
846
847 return persistenceManagers;
848 }
849
850
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000851 private ServiceReference getServiceReference()
852 {
853 ServiceRegistration reg = configurationAdminRegistration;
Felix Meschberger0770cad2012-06-11 12:36:52 +0000854 if (reg != null) {
855 return reg.getReference();
856 }
857
858 // probably called for firing an event during service registration
859 // since we didn't get the service registration yet we use the
860 // service registry to get our service reference
861 BundleContext context = bundleContext;
862 if ( context != null )
863 {
864 try
865 {
866 ServiceReference[] refs = context.getServiceReferences( ConfigurationAdmin.class.getName(), null );
867 if ( refs != null )
868 {
869 for ( int i = 0; i < refs.length; i++ )
870 {
871 if ( refs[i].getBundle().getBundleId() == context.getBundle().getBundleId() )
872 {
873 return refs[i];
874 }
875 }
876 }
877 }
878 catch ( InvalidSyntaxException e )
879 {
880 // unexpected since there is no filter
881 }
882 }
883
884 // service references
885 return null;
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000886 }
887
888
Felix Meschberger05d89e12011-11-03 23:37:10 +0000889 /**
890 * Configures the ManagedService and returns the service.pid
891 * service property as a String[], which may be <code>null</code> if
892 * the ManagedService does not have such a property.
893 */
Felix Meschberger05d89e12011-11-03 23:37:10 +0000894 /**
895 * Configures the ManagedServiceFactory and returns the service.pid
896 * service property as a String[], which may be <code>null</code> if
897 * the ManagedServiceFactory does not have such a property.
898 */
Felix Meschberger382a19b2012-07-03 09:45:14 +0000899 /**
900 * Schedules the configuration of the referenced service with
901 * configuration for the given PID.
902 *
Felix Meschberger273985f2012-07-05 12:28:06 +0000903 * @param pid The list of service PID of the configurations to be
904 * provided to the referenced service.
Felix Meschberger382a19b2012-07-03 09:45:14 +0000905 * @param sr The <code>ServiceReference</code> to the service
906 * to be configured.
907 * @param factory <code>true</code> If the service is considered to
908 * be a <code>ManagedServiceFactory</code>. Otherwise the service
909 * is considered to be a <code>ManagedService</code>.
910 */
Felix Meschberger3cbf4652012-10-18 06:49:39 +0000911 public void configure( String[] pid, ServiceReference sr, final boolean factory, final ConfigurationMap<?> configs )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000912 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000913 if ( this.isLogEnabled( LogService.LOG_DEBUG ) )
914 {
915 this.log( LogService.LOG_DEBUG, "configure(ManagedService {0})", new Object[]
916 { toString( sr ) } );
917 }
918
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000919 Runnable r;
920 if ( factory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000921 {
Felix Meschberger3cbf4652012-10-18 06:49:39 +0000922 r = new ManagedServiceFactoryUpdate( pid, sr, configs );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000923 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000924 else
925 {
Felix Meschberger3cbf4652012-10-18 06:49:39 +0000926 r = new ManagedServiceUpdate( pid, sr, configs );
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000927 }
928 updateThread.schedule( r );
929 log( LogService.LOG_DEBUG, "[{0}] scheduled", new Object[]
930 { r } );
Felix Meschberger851c6412009-08-16 18:43:26 +0000931 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000932
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000933
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000934 /**
935 * Factory method to create a new configuration object. The configuration
936 * object returned is not stored in configuration cache and only persisted
937 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000938 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000939 * @param pid
940 * The PID of the new configuration object. Must not be
941 * <code>null</code>.
942 * @param factoryPid
943 * The factory PID of the new configuration. Not
Felix Meschberger6a698df2009-08-16 18:38:46 +0000944 * <code>null</code> if the new configuration object belongs to a
945 * factory. The configuration object will not be persisted if
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000946 * this parameter is not <code>null</code>.
947 * @param bundleLocation
948 * The bundle location of the bundle to which the configuration
Felix Meschberger6a698df2009-08-16 18:38:46 +0000949 * belongs or <code>null</code> if the configuration is not bound
950 * yet.
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000951 * @return The new configuration object
952 * @throws IOException
953 * May be thrown if an error occurrs persisting the new
954 * configuration object.
955 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000956 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000957 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000958 log( LogService.LOG_DEBUG, "createConfiguration({0}, {1}, {2})", new Object[]
959 { pid, factoryPid, bundleLocation } );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000960 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000961 }
962
963
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000964 /**
965 * Returns a list of {@link Factory} instances according to the
966 * Configuration Admin 1.5 specification for targeted PIDs (Section
967 * 104.3.2)
968 *
969 * @param rawFactoryPid The raw factory PID without any targetting.
970 * @param target The <code>ServiceReference</code> of the service to
971 * be supplied with targeted configuration.
972 * @return A list of {@link Factory} instances as listed above. This
973 * list will always at least include an instance for the
974 * <code>rawFactoryPid</code>. Other instances are only included
975 * if existing.
976 * @throws IOException If an error occurrs reading any of the
977 * {@link Factory} instances from persistence
978 */
979 List<Factory> getTargetedFactories( final String rawFactoryPid, final ServiceReference target ) throws IOException
980 {
981 LinkedList<Factory> factories = new LinkedList<Factory>();
982
983 final Bundle serviceBundle = target.getBundle();
984 if ( serviceBundle != null )
985 {
986 // for pre-1.5 API compatibility
987 final StringBuffer targetedPid = new StringBuffer( rawFactoryPid );
988 factories.add( getOrCreateFactory( targetedPid.toString() ) );
989
990 targetedPid.append( '|' ).append( serviceBundle.getSymbolicName() );
991 Factory f = getFactory( targetedPid.toString() );
992 if ( f != null )
993 {
994 factories.add( 0, f );
995 }
996
997 targetedPid.append( '|' ).append( TargetedPID.getBundleVersion( serviceBundle ) );
998 f = getFactory( targetedPid.toString() );
999 if ( f != null )
1000 {
1001 factories.add( 0, f );
1002 }
1003
1004 targetedPid.append( '|' ).append( serviceBundle.getLocation() );
1005 f = getFactory( targetedPid.toString() );
1006 if ( f != null )
1007 {
1008 factories.add( 0, f );
1009 }
1010 }
1011
1012 return factories;
1013 }
1014
1015
1016 /**
1017 * Gets the factory with the exact identifier from the cached or from
1018 * the persistence managers. If no factory exists already one is
1019 * created and cached.
1020 *
1021 * @param factoryPid The PID of the {@link Factory} to return
1022 * @return The existing or newly created {@link Factory}
1023 * @throws IOException If an error occurrs reading the factory from
1024 * a {@link PersistenceManager}
1025 */
1026 Factory getOrCreateFactory( String factoryPid ) throws IOException
1027 {
1028 Factory factory = getFactory( factoryPid );
1029 if ( factory != null )
1030 {
1031 return factory;
1032 }
1033
1034 return createFactory( factoryPid );
1035 }
1036
1037
1038 /**
1039 * Gets the factory with the exact identifier from the cached or from
1040 * the persistence managers. If no factory exists <code>null</code>
1041 * is returned.
1042 *
1043 * @param factoryPid The PID of the {@link Factory} to return
1044 * @return The existing {@link Factory} or <code>null</code>
1045 * @throws IOException If an error occurrs reading the factory from
1046 * a {@link PersistenceManager}
1047 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001048 Factory getFactory( String factoryPid ) throws IOException
1049 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001050 // check for cached factory
Felix Meschbergerf4631322008-03-10 12:32:35 +00001051 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001052 if ( factory != null )
1053 {
1054 return factory;
1055 }
1056
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001057 // try to load factory from persistence
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001058 PersistenceManager[] pmList = getPersistenceManagers();
1059 for ( int i = 0; i < pmList.length; i++ )
1060 {
1061 if ( Factory.exists( pmList[i], factoryPid ) )
1062 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +00001063 factory = Factory.load( this, pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001064 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001065 return factory;
1066 }
1067 }
1068
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001069 // no existing factory
1070 return null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001071 }
1072
1073
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001074 /**
1075 * Creates a new factory with the given <code>factoryPid</code>.
1076 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001077 Factory createFactory( String factoryPid )
1078 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +00001079 Factory factory = new Factory( this, getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001080 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001081 return factory;
1082 }
1083
1084
Felix Meschberger2941ef92007-08-20 13:15:16 +00001085 /**
1086 * Calls the registered configuration plugins on the given configuration
Felix Meschberger273985f2012-07-05 12:28:06 +00001087 * properties from the given configuration object.
1088 * <p>
1089 * The plugins to be called are selected as <code>ConfigurationPlugin</code>
1090 * services registered with a <code>cm.target</code> property set to
1091 * <code>*</code> or the factory PID of the configuration (for factory
1092 * configurations) or the PID of the configuration (for non-factory
1093 * configurations).
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001094 *
Felix Meschberger41cce522009-08-19 05:54:40 +00001095 * @param props The configuraiton properties run through the registered
Felix Meschberger273985f2012-07-05 12:28:06 +00001096 * ConfigurationPlugin services. This must not be
1097 * <code>null</code>.
Felix Meschberger2941ef92007-08-20 13:15:16 +00001098 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001099 * is to be updated with configuration
Felix Meschberger273985f2012-07-05 12:28:06 +00001100 * @param configPid The PID of the configuration object whose properties
1101 * are to be augmented
1102 * @param factoryPid the factory PID of the configuration object whose
1103 * properties are to be augmented. This is non-<code>null</code>
1104 * only for a factory configuration.
Felix Meschberger2941ef92007-08-20 13:15:16 +00001105 */
Felix Meschberger273985f2012-07-05 12:28:06 +00001106 public void callPlugins( final Dictionary props, final ServiceReference sr, final String configPid,
1107 final String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001108 {
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001109 ServiceReference[] plugins = null;
1110 try
1111 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001112 final String targetPid = (factoryPid == null) ? configPid : factoryPid;
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001113 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001114 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001115 }
1116 catch ( InvalidSyntaxException ise )
1117 {
1118 // no filter, no exception ...
1119 }
1120
1121 // abort early if there are no plugins
1122 if ( plugins == null || plugins.length == 0 )
1123 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001124 return;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001125 }
1126
1127 // sort the plugins by their service.cmRanking
Felix Meschberger007c50e2011-10-20 12:39:38 +00001128 if ( plugins.length > 1 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001129 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001130 Arrays.sort( plugins, RankingComparator.CM_RANKING );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001131 }
1132
1133 // call the plugins in order
Felix Meschberger007c50e2011-10-20 12:39:38 +00001134 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001135 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001136 ServiceReference pluginRef = plugins[i];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001137 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001138 if ( plugin != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001139 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001140 try
1141 {
1142 plugin.modifyConfiguration( sr, props );
1143 }
1144 catch ( Throwable t )
1145 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001146 log( LogService.LOG_ERROR, "Unexpected problem calling configuration plugin {0}", new Object[]
1147 { toString( pluginRef ), t } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001148 }
1149 finally
1150 {
1151 // ensure ungetting the plugin
1152 bundleContext.ungetService( pluginRef );
1153 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001154 ConfigurationImpl.setAutoProperties( props, configPid, factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001155 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001156 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001157 }
1158
1159
1160 /**
1161 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001162 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001163 * @param factoryPid
1164 * @return
1165 */
1166 private static String createPid( String factoryPid )
1167 {
Felix Meschberger417f66c2011-02-04 11:25:23 +00001168 Random ng = numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001169 if ( ng == null )
1170 {
Felix Meschberger417f66c2011-02-04 11:25:23 +00001171 // FELIX-2771 Secure Random not available on Mika
1172 try
1173 {
1174 ng = new SecureRandom();
1175 }
1176 catch ( Throwable t )
1177 {
1178 // fall back to Random
1179 ng = new Random();
1180 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001181 }
1182
1183 byte[] randomBytes = new byte[16];
1184 ng.nextBytes( randomBytes );
1185 randomBytes[6] &= 0x0f; /* clear version */
1186 randomBytes[6] |= 0x40; /* set to version 4 */
1187 randomBytes[8] &= 0x3f; /* clear variant */
1188 randomBytes[8] |= 0x80; /* set to IETF variant */
1189
1190 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
1191
1192 // prefix the new pid with the factory pid
1193 buf.append( factoryPid ).append( "." );
1194
1195 // serialize the UUID into the buffer
1196 for ( int i = 0; i < randomBytes.length; i++ )
1197 {
1198
1199 if ( i == 4 || i == 6 || i == 8 || i == 10 )
1200 {
1201 buf.append( '-' );
1202 }
1203
1204 int val = randomBytes[i] & 0xff;
1205 buf.append( Integer.toHexString( val >> 4 ) );
1206 buf.append( Integer.toHexString( val & 0xf ) );
1207 }
1208
1209 return buf.toString();
1210 }
1211
1212
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001213 public boolean isLogEnabled( int level )
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001214 {
1215 return level <= logLevel;
1216 }
1217
1218
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001219 public void log( int level, String format, Object[] args )
Felix Meschberger4f269292011-10-21 13:52:31 +00001220 {
1221 if ( isLogEnabled( level ) )
1222 {
1223 Throwable throwable = null;
1224 String message = format;
1225
1226 if ( args != null && args.length > 0 )
1227 {
1228 if ( args[args.length - 1] instanceof Throwable )
1229 {
1230 throwable = ( Throwable ) args[args.length - 1];
1231 }
1232 message = MessageFormat.format( format, args );
1233 }
1234
1235 log( level, message, throwable );
1236 }
1237 }
1238
1239
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001240 public void log( int level, String message, Throwable t )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001241 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001242 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +00001243 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001244 if ( log != null )
1245 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +00001246 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001247 return;
1248 }
1249
Felix Meschberger08282c32009-01-28 07:01:55 +00001250 // Otherwise only log if more serious than the configured level
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001251 if ( isLogEnabled( level ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001252 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001253 String code;
1254 switch ( level )
1255 {
1256 case LogService.LOG_INFO:
1257 code = "*INFO *";
1258 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001259
Felix Meschberger08282c32009-01-28 07:01:55 +00001260 case LogService.LOG_WARNING:
1261 code = "*WARN *";
1262 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001263
Felix Meschberger08282c32009-01-28 07:01:55 +00001264 case LogService.LOG_ERROR:
1265 code = "*ERROR*";
1266 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001267
Felix Meschberger08282c32009-01-28 07:01:55 +00001268 case LogService.LOG_DEBUG:
1269 default:
1270 code = "*DEBUG*";
1271 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001272
Felix Meschberger08282c32009-01-28 07:01:55 +00001273 System.err.println( code + " " + message );
1274 if ( t != null )
1275 {
1276 t.printStackTrace( System.err );
1277 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001278 }
1279 }
1280
Felix Meschberger851c6412009-08-16 18:43:26 +00001281
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001282 public static String toString( ServiceReference ref )
Felix Meschberger41cce522009-08-19 05:54:40 +00001283 {
1284 String[] ocs = ( String[] ) ref.getProperty( "objectClass" );
Felix Meschberger382a19b2012-07-03 09:45:14 +00001285 StringBuffer buf = new StringBuffer( "[" );
Felix Meschberger41cce522009-08-19 05:54:40 +00001286 for ( int i = 0; i < ocs.length; i++ )
1287 {
Felix Meschberger382a19b2012-07-03 09:45:14 +00001288 buf.append( ocs[i] );
Felix Meschberger41cce522009-08-19 05:54:40 +00001289 if ( i < ocs.length - 1 )
Felix Meschberger382a19b2012-07-03 09:45:14 +00001290 buf.append( ", " );
Felix Meschberger41cce522009-08-19 05:54:40 +00001291 }
1292
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001293 buf.append( ", id=" ).append( ref.getProperty( Constants.SERVICE_ID ) );
1294
1295 Bundle provider = ref.getBundle();
1296 if ( provider != null )
1297 {
1298 buf.append( ", bundle=" ).append( provider.getBundleId() );
Felix Meschberger0135b322011-11-16 12:30:22 +00001299 buf.append( '/' ).append( provider.getLocation() );
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001300 }
1301 else
1302 {
1303 buf.append( ", unregistered" );
1304 }
1305
1306 buf.append( "]" );
1307 return buf.toString();
Felix Meschberger41cce522009-08-19 05:54:40 +00001308 }
1309
Felix Meschbergerce67d732009-08-20 06:26:35 +00001310
Felix Meschberger007c50e2011-10-20 12:39:38 +00001311 /**
1312 * Checks whether the bundle is allowed to receive the configuration
1313 * with the given location binding.
1314 * <p>
1315 * This method implements the logic defined CM 1.4 / 104.4.1:
1316 * <ul>
1317 * <li>If the location is <code>null</code> (the configuration is not
1318 * bound yet), assume the bundle is allowed</li>
1319 * <li>If the location is a single location (no leading "?"), require
1320 * the bundle's location to match</li>
1321 * <li>If the location is a multi-location (leading "?"), assume the
1322 * bundle is allowed if there is no security manager. If there is a
1323 * security manager, check whether the bundle has "target" permission
1324 * on this location.</li>
1325 * </ul>
1326 */
1327 boolean canReceive( final Bundle bundle, final String location )
1328 {
1329 if ( location == null )
1330 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001331 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration=(unbound)", new Object[]
Felix Meschberger61207232011-11-17 10:06:45 +00001332 { bundle.getLocation() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001333 return true;
1334 }
1335 else if ( location.startsWith( "?" ) )
1336 {
1337 // multi-location
1338 if ( System.getSecurityManager() != null )
1339 {
Felix Meschberger61207232011-11-17 10:06:45 +00001340 final boolean hasPermission = bundle.hasPermission( new ConfigurationPermission( location,
1341 ConfigurationPermission.TARGET ) );
1342 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2} (SecurityManager check)",
1343 new Object[]
1344 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1345 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001346 }
Felix Meschberger61207232011-11-17 10:06:45 +00001347
1348 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration={1} (no SecurityManager)",
1349 new Object[]
1350 { bundle.getLocation(), location } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001351 return true;
1352 }
1353 else
1354 {
1355 // single location, must match
Felix Meschberger61207232011-11-17 10:06:45 +00001356 final boolean hasPermission = location.equals( bundle.getLocation() );
1357 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2}", new Object[]
1358 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1359 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001360 }
1361 }
1362
Felix Meschberger61207232011-11-17 10:06:45 +00001363
Felix Meschberger007c50e2011-10-20 12:39:38 +00001364 // ---------- inner classes
1365
Felix Meschberger007c50e2011-10-20 12:39:38 +00001366 /**
1367 * The <code>ManagedServiceUpdate</code> updates a freshly registered
1368 * <code>ManagedService</code> with a specific configuration. If a
1369 * ManagedService is registered with multiple PIDs an instance of this
1370 * class is used for each registered PID.
1371 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001372 private class ManagedServiceUpdate implements Runnable
1373 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001374 private final String[] pids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001375
Felix Meschberger41cce522009-08-19 05:54:40 +00001376 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001377
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001378 private final ConfigurationMap<?> configs;
1379
1380
1381 ManagedServiceUpdate( String[] pids, ServiceReference sr, ConfigurationMap<?> configs )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001382 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001383 this.pids = pids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001384 this.sr = sr;
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001385 this.configs = configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001386 }
1387
1388
1389 public void run()
1390 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001391 for ( String pid : this.pids )
1392 {
1393 try
1394 {
1395 final ConfigurationImpl config = getTargetedConfiguration( pid, this.sr );
1396 provide( pid, config );
1397 }
1398 catch ( IOException ioe )
1399 {
1400 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1401 { pid, ioe } );
1402 }
1403 catch ( Exception e )
1404 {
1405 log( LogService.LOG_ERROR, "Unexpected problem providing configuration {0} to service {1}",
1406 new Object[]
1407 { pid, ConfigurationManager.toString( this.sr ), e } );
1408 }
1409 }
1410 }
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001411
Felix Meschberger273985f2012-07-05 12:28:06 +00001412
1413 private void provide(final String servicePid, final ConfigurationImpl config)
1414 {
1415 // check configuration
1416 final TargetedPID configPid;
1417 final Dictionary properties;
1418 final long revision;
Felix Meschberger41cce522009-08-19 05:54:40 +00001419 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001420 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001421 synchronized ( config )
Felix Meschberger41243192009-01-14 19:59:58 +00001422 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001423 configPid = config.getPid();
1424 properties = config.getProperties( true );
1425 revision = config.getRevision();
Felix Meschberger41243192009-01-14 19:59:58 +00001426 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001427 }
1428 else
1429 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001430 // 104.5.3 ManagedService.updated must be called with null
1431 // if no configuration is available
Felix Meschberger273985f2012-07-05 12:28:06 +00001432 configPid = new TargetedPID( servicePid );
Felix Meschberger41cce522009-08-19 05:54:40 +00001433 properties = null;
Felix Meschberger273985f2012-07-05 12:28:06 +00001434 revision = -1;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001435 }
1436
Felix Meschberger273985f2012-07-05 12:28:06 +00001437 log( LogService.LOG_DEBUG, "Updating service {0} with configuration {1}@{2}", new Object[]
1438 { servicePid, configPid, new Long( revision ) } );
1439
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001440 managedServiceTracker.provideConfiguration( sr, configPid, null, properties, revision, this.configs );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001441 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001442
Felix Meschberger432e3872008-03-07 14:58:57 +00001443 public String toString()
1444 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001445 return "ManagedService Update: pid=" + Arrays.asList( pids );
Felix Meschberger432e3872008-03-07 14:58:57 +00001446 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001447 }
1448
Felix Meschberger007c50e2011-10-20 12:39:38 +00001449 /**
1450 * The <code>ManagedServiceFactoryUpdate</code> updates a freshly
1451 * registered <code>ManagedServiceFactory</code> with a specific
1452 * configuration. If a ManagedServiceFactory is registered with
1453 * multiple PIDs an instance of this class is used for each registered
1454 * PID.
1455 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001456 private class ManagedServiceFactoryUpdate implements Runnable
1457 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001458 private final String[] factoryPids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001459
Felix Meschberger41cce522009-08-19 05:54:40 +00001460 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001461
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001462 private final ConfigurationMap<?> configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001463
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001464
1465 ManagedServiceFactoryUpdate( String[] factoryPids, ServiceReference sr, final ConfigurationMap<?> configs )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001466 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001467 this.factoryPids = factoryPids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001468 this.sr = sr;
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001469 this.configs = configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001470 }
1471
1472
1473 public void run()
1474 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001475 for ( String factoryPid : this.factoryPids )
1476 {
1477
1478 List<Factory> factories = null;
1479 try
1480 {
1481 factories = getTargetedFactories( factoryPid, sr );
1482 for ( Factory factory : factories )
1483 {
1484 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
1485 {
1486 final String pid = ( String ) pi.next();
1487 ConfigurationImpl cfg;
1488 try
1489 {
1490 cfg = getConfiguration( pid );
1491 }
1492 catch ( IOException ioe )
1493 {
1494 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1495 { pid, ioe } );
1496 continue;
1497 }
1498
1499 // sanity check on the configuration
1500 if ( cfg == null )
1501 {
1502 log( LogService.LOG_ERROR,
1503 "Configuration {0} referred to by factory {1} does not exist", new Object[]
1504 { pid, factoryPid } );
1505 factory.removePID( pid );
1506 factory.storeSilently();
1507 continue;
1508 }
1509 else if ( cfg.isNew() )
1510 {
1511 // Configuration has just been created but not yet updated
1512 // we currently just ignore it and have the update mechanism
1513 // provide the configuration to the ManagedServiceFactory
1514 // As of FELIX-612 (not storing new factory configurations)
1515 // this should not happen. We keep this for added stability
1516 // but raise the logging level to error.
1517 log( LogService.LOG_ERROR, "Ignoring new configuration pid={0}", new Object[]
1518 { pid } );
1519 continue;
1520 }
1521
1522 /*
1523 * this code would catch targeted factory PIDs;
1524 * since this is not expected any way, we can
1525 * leave this out
1526 */
1527 /*
1528 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1529 {
1530 log( LogService.LOG_ERROR,
1531 "Configuration {0} referred to by factory {1} seems to belong to factory {2}",
1532 new Object[]
1533 { pid, factoryPid, cfg.getFactoryPid() } );
1534 factory.removePID( pid );
1535 factory.storeSilently();
1536 continue;
1537 }
1538 */
1539
1540 provide( factoryPid, cfg );
1541 }
1542 }
1543 }
1544 catch ( IOException ioe )
1545 {
1546 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID {0}", new Object[]
1547 { factoryPid, ioe } );
1548 }
1549 }
1550 }
1551
1552
1553 private void provide(final String factoryPid, final ConfigurationImpl config) {
1554
1555 final Dictionary rawProperties;
1556 final long revision;
1557 synchronized ( config )
1558 {
1559 rawProperties = config.getProperties( true );
1560 revision = config.getRevision();
1561 }
1562
1563 log( LogService.LOG_DEBUG, "Updating service {0} with configuration {1}/{2}@{3}", new Object[]
1564 { factoryPid, config.getFactoryPid(), config.getPid(), new Long( revision ) } );
1565
1566 // CM 1.4 / 104.13.2.1
1567 final Bundle serviceBundle = this.sr.getBundle();
Felix Meschberger41243192009-01-14 19:59:58 +00001568 if ( serviceBundle == null )
1569 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001570 log(
1571 LogService.LOG_INFO,
1572 "ManagedServiceFactory for factory PID {0} seems to already have been unregistered, not updating with factory",
1573 new Object[]
1574 { factoryPid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001575 return;
1576 }
1577
Felix Meschberger273985f2012-07-05 12:28:06 +00001578 if ( !canReceive( serviceBundle, config.getBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001579 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001580 log( LogService.LOG_ERROR,
1581 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001582 new Object[]
Felix Meschberger273985f2012-07-05 12:28:06 +00001583 { config.getPid(), ConfigurationManager.toString( sr ), config.getBundleLocation() } );
1584
1585 // no service, really, bail out
1586 return;
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001587 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001588
1589 // 104.4.2 Dynamic Binding
1590 config.tryBindLocation( serviceBundle.getLocation() );
1591
1592 // update the service with the configuration (if non-null)
1593 if ( rawProperties != null )
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001594 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001595 log( LogService.LOG_DEBUG, "{0}: Updating configuration pid={1}", new Object[]
1596 { ConfigurationManager.toString( sr ), config.getPid() } );
1597 managedServiceFactoryTracker.provideConfiguration( sr, config.getPid(), config.getFactoryPid(),
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001598 rawProperties, revision, this.configs );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001599 }
1600 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001601
1602
Felix Meschberger432e3872008-03-07 14:58:57 +00001603 public String toString()
1604 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001605 return "ManagedServiceFactory Update: factoryPid=" + Arrays.asList( this.factoryPids );
Felix Meschberger432e3872008-03-07 14:58:57 +00001606 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001607 }
1608
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001609 private abstract class ConfigurationProvider<T> implements Runnable
1610 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001611
1612 protected final ConfigurationImpl config;
1613 protected final long revision;
1614 protected final Dictionary<String, ?> properties;
Felix Meschbergerfffde292012-11-18 18:02:20 +00001615 private BaseTracker<T> helper;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001616
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001617
1618 protected ConfigurationProvider( final ConfigurationImpl config )
1619 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001620 synchronized ( config )
1621 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001622 this.config = config;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001623 this.revision = config.getRevision();
1624 this.properties = config.getProperties( true );
1625 }
1626 }
1627
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001628
1629 protected TargetedPID getTargetedServicePid()
1630 {
1631 final TargetedPID factoryPid = this.config.getFactoryPid();
1632 if ( factoryPid != null )
1633 {
1634 return factoryPid;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001635 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001636 return this.config.getPid();
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001637 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001638
1639
Felix Meschbergerfffde292012-11-18 18:02:20 +00001640 protected BaseTracker<T> getHelper()
1641 {
1642 if ( this.helper == null )
1643 {
1644 this.helper = ( BaseTracker<T> ) ( ( this.config.getFactoryPid() == null ) ? ConfigurationManager.this.managedServiceTracker
1645 : ConfigurationManager.this.managedServiceFactoryTracker );
1646 }
1647 return this.helper;
1648 }
1649
1650
Felix Meschberger273985f2012-07-05 12:28:06 +00001651 protected boolean provideReplacement( ServiceReference<T> sr )
1652 {
1653 if ( this.config.getFactoryPid() == null )
1654 {
1655 try
1656 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001657 final String configPidString = this.getHelper().getServicePid( sr, this.config.getPid() );
Pierre De Rop10c313c2014-02-03 15:22:04 +00001658 if (configPidString == null) {
1659 return false; // The managed service is not registered anymore in the OSGi service registry.
1660 }
Felix Meschberger1ff5c532012-07-08 18:23:08 +00001661 final ConfigurationImpl rc = getTargetedConfiguration( configPidString, sr );
Felix Meschberger273985f2012-07-05 12:28:06 +00001662 if ( rc != null )
1663 {
1664 final TargetedPID configPid;
1665 final Dictionary properties;
1666 final long revision;
Felix Meschbergercd5195f2012-07-05 17:17:45 +00001667 synchronized ( rc )
Felix Meschberger273985f2012-07-05 12:28:06 +00001668 {
Felix Meschbergercd5195f2012-07-05 17:17:45 +00001669 configPid = rc.getPid();
1670 properties = rc.getProperties( true );
1671 revision = rc.getRevision();
Felix Meschberger273985f2012-07-05 12:28:06 +00001672 }
1673
Felix Meschbergerfffde292012-11-18 18:02:20 +00001674 this.getHelper().provideConfiguration( sr, configPid, null, properties, -revision, null );
Felix Meschberger273985f2012-07-05 12:28:06 +00001675
1676 return true;
1677 }
1678 }
1679 catch ( IOException ioe )
1680 {
1681 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1682 { this.config.getPid(), ioe } );
1683 }
1684 catch ( Exception e )
1685 {
1686 log( LogService.LOG_ERROR, "Unexpected problem providing configuration {0} to service {1}",
1687 new Object[]
1688 { this.config.getPid(), ConfigurationManager.toString( sr ), e } );
1689 }
1690 }
1691
1692 // factory or no replacement available
1693 return false;
1694 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001695 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001696
1697 /**
1698 * The <code>UpdateConfiguration</code> is used to update
1699 * <code>ManagedService[Factory]</code> services with the configuration
1700 * they are subscribed to. This may cause the configuration to be
1701 * supplied to multiple services.
1702 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001703 private class UpdateConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001704 {
1705
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001706 UpdateConfiguration( final ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001707 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001708 super( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001709 }
1710
1711
1712 public void run()
1713 {
Felix Meschberger61207232011-11-17 10:06:45 +00001714 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1715 { config.getPid(), new Long( revision ) } );
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001716
Felix Meschbergerfffde292012-11-18 18:02:20 +00001717 final List<ServiceReference<?>> srList = this.getHelper().getServices( getTargetedServicePid() );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001718 if ( !srList.isEmpty() )
Felix Meschberger41cce522009-08-19 05:54:40 +00001719 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001720 // optionally bind dynamically to the first service
Pierre De Rop10c313c2014-02-03 15:22:04 +00001721 Bundle bundle = srList.get(0).getBundle();
1722 if (bundle == null) {
1723 log( LogService.LOG_DEBUG,
1724 "Service {0} seems to be unregistered concurrently (not providing configuration)",
1725 new Object[]
1726 { ConfigurationManager.toString( srList.get(0) ) } );
1727 return;
1728 }
1729 config.tryBindLocation( bundle.getLocation() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001730
1731 final String configBundleLocation = config.getBundleLocation();
1732
1733 // provide configuration to all services from the
1734 // correct bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001735 for (ServiceReference<?> ref : srList)
Felix Meschberger41cce522009-08-19 05:54:40 +00001736 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001737 final Bundle refBundle = ref.getBundle();
1738 if ( refBundle == null )
Felix Meschberger41cce522009-08-19 05:54:40 +00001739 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001740 log( LogService.LOG_DEBUG,
1741 "Service {0} seems to be unregistered concurrently (not providing configuration)",
1742 new Object[]
1743 { ConfigurationManager.toString( ref ) } );
1744 }
1745 else if ( canReceive( refBundle, configBundleLocation ) )
1746 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001747 this.getHelper().provideConfiguration( ref, this.config.getPid(), this.config.getFactoryPid(),
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001748 this.properties, this.revision, null );
Felix Meschberger2444da62011-11-17 11:17:50 +00001749 }
1750 else
1751 {
1752 // CM 1.4 / 104.13.2.2
Felix Meschberger4f269292011-10-21 13:52:31 +00001753 log( LogService.LOG_ERROR,
1754 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1755 new Object[]
1756 { config.getPid(), ConfigurationManager.toString( ref ), configBundleLocation } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001757 }
1758
Felix Meschberger41cce522009-08-19 05:54:40 +00001759 }
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001760 }
Felix Meschberger137ee722011-11-16 09:51:59 +00001761 else if ( isLogEnabled( LogService.LOG_DEBUG ) )
1762 {
Felix Meschberger1ee888d2011-11-16 12:42:57 +00001763 log( LogService.LOG_DEBUG, "No ManagedService[Factory] registered for updates to configuration {0}",
Felix Meschberger137ee722011-11-16 09:51:59 +00001764 new Object[]
1765 { config.getPid() } );
1766 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001767 }
1768
1769
Felix Meschberger432e3872008-03-07 14:58:57 +00001770 public String toString()
1771 {
1772 return "Update: pid=" + config.getPid();
1773 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001774 }
1775
Felix Meschberger007c50e2011-10-20 12:39:38 +00001776
1777 /**
1778 * The <code>DeleteConfiguration</code> class is used to inform
1779 * <code>ManagedService[Factory]</code> services of a configuration
1780 * being deleted.
1781 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001782 private class DeleteConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001783 {
Felix Meschberger66423332007-08-22 08:46:34 +00001784
Felix Meschbergerc12db8c2009-08-19 06:43:59 +00001785 private final String configLocation;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001786
1787
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001788 DeleteConfiguration( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001789 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001790 /*
1791 * NOTE: We keep the configuration because it might be cleared just
1792 * after calling this method. The pid and factoryPid fields are
1793 * final and cannot be reset.
1794 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001795 super(config);
Felix Meschberger007c50e2011-10-20 12:39:38 +00001796 this.configLocation = config.getBundleLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001797 }
1798
1799
1800 public void run()
1801 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001802 List<ServiceReference<?>> srList = this.getHelper().getServices( getTargetedServicePid() );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001803 if ( !srList.isEmpty() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001804 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001805 for (ServiceReference<?> sr : srList)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001806 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001807 final Bundle srBundle = sr.getBundle();
1808 if ( srBundle == null )
1809 {
1810 log( LogService.LOG_DEBUG,
1811 "Service {0} seems to be unregistered concurrently (not removing configuration)",
1812 new Object[]
1813 { ConfigurationManager.toString( sr ) } );
1814 }
1815 else if ( canReceive( srBundle, configLocation ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001816 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001817 // revoke configuration unless a replacement
1818 // configuration can be provided
1819 if ( !this.provideReplacement( sr ) )
1820 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001821 this.getHelper().removeConfiguration( sr, this.config.getPid(), this.config.getFactoryPid() );
Felix Meschberger273985f2012-07-05 12:28:06 +00001822 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001823 }
Felix Meschberger2444da62011-11-17 11:17:50 +00001824 else
1825 {
1826 // CM 1.4 / 104.13.2.2
1827 log( LogService.LOG_ERROR,
1828 "Cannot remove configuration {0} for {1}: No visibility to configuration bound to {2}",
1829 new Object[]
1830 { config.getPid(), ConfigurationManager.toString( sr ), configLocation } );
1831 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001832 }
1833 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001834
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001835 final TargetedPID factoryPid = config.getFactoryPid();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001836 if ( factoryPid != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001837 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001838 // remove the pid from the factory
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001839 final String pid = config.getPidString();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001840 try
1841 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001842 Factory factory = getOrCreateFactory( factoryPid.toString() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001843 factory.removePID( pid );
1844 factory.store();
1845 }
1846 catch ( IOException ioe )
1847 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001848 log( LogService.LOG_ERROR, "Failed removing {0} from the factory {1}", new Object[]
1849 { pid, factoryPid, ioe } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001850 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001851 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001852 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001853
Felix Meschberger432e3872008-03-07 14:58:57 +00001854 public String toString()
1855 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001856 return "Delete: pid=" + config.getPid();
Felix Meschberger432e3872008-03-07 14:58:57 +00001857 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001858 }
1859
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001860 private class LocationChanged extends ConfigurationProvider
Felix Meschberger007c50e2011-10-20 12:39:38 +00001861 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001862 private final String oldLocation;
1863
1864
1865 LocationChanged( ConfigurationImpl config, String oldLocation )
1866 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001867 super( config );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001868 this.oldLocation = oldLocation;
1869 }
1870
1871
1872 public void run()
1873 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001874 List<ServiceReference<?>> srList = this.getHelper().getServices( getTargetedServicePid() );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001875 if ( !srList.isEmpty() )
Felix Meschberger007c50e2011-10-20 12:39:38 +00001876 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001877 for (final ServiceReference<?> sr : srList)
Felix Meschberger007c50e2011-10-20 12:39:38 +00001878 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001879 final Bundle srBundle = sr.getBundle();
1880 if ( srBundle == null )
1881 {
1882 log( LogService.LOG_DEBUG,
1883 "Service {0} seems to be unregistered concurrently (not processing)", new Object[]
1884 { ConfigurationManager.toString( sr ) } );
1885 continue;
1886 }
1887
1888 final boolean wasVisible = canReceive( srBundle, oldLocation );
1889 final boolean isVisible = canReceive( srBundle, config.getBundleLocation() );
1890
1891 // make sure the config is dynamically bound to the first
1892 // service if the config has been unbound causing this update
1893 if ( isVisible )
1894 {
1895 config.tryBindLocation( srBundle.getLocation() );
1896 }
1897
Felix Meschberger007c50e2011-10-20 12:39:38 +00001898 if ( wasVisible && !isVisible )
1899 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001900 // revoke configuration unless a replacement
1901 // configuration can be provided
1902 if ( !this.provideReplacement( sr ) )
1903 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001904 this.getHelper().removeConfiguration( sr, this.config.getPid(), this.config.getFactoryPid() );
Felix Meschberger273985f2012-07-05 12:28:06 +00001905 log( LogService.LOG_DEBUG, "Configuration {0} revoked from {1} (no more visibility)",
1906 new Object[]
1907 { config.getPid(), ConfigurationManager.toString( sr ) } );
1908 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001909 }
1910 else if ( !wasVisible && isVisible )
1911 {
1912 // call updated method
Felix Meschbergerfffde292012-11-18 18:02:20 +00001913 this.getHelper().provideConfiguration( sr, this.config.getPid(), this.config.getFactoryPid(),
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001914 this.properties, this.revision, null );
Felix Meschberger4f269292011-10-21 13:52:31 +00001915 log( LogService.LOG_DEBUG, "Configuration {0} provided to {1} (new visibility)", new Object[]
1916 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger35658d52011-10-20 21:43:58 +00001917 }
Felix Meschberger4f269292011-10-21 13:52:31 +00001918 else
Felix Meschberger35658d52011-10-20 21:43:58 +00001919 {
1920 // same visibility as before
Felix Meschberger4f269292011-10-21 13:52:31 +00001921 log( LogService.LOG_DEBUG, "Unmodified visibility to configuration {0} for {1}", new Object[]
1922 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001923 }
1924 }
1925 }
1926 }
1927
1928
1929 public String toString()
1930 {
1931 return "Location Changed (pid=" + config.getPid() + "): " + oldLocation + " ==> "
1932 + config.getBundleLocation();
1933 }
1934 }
1935
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001936 private class FireConfigurationEvent implements Runnable
1937 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001938 private final int type;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001939
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001940 private final String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001941
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001942 private final String factoryPid;
1943
1944 private final ServiceReference[] listenerReferences;
1945
1946 private final ConfigurationListener[] listeners;
1947
1948 private final Bundle[] listenerProvider;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001949
Felix Meschberger0770cad2012-06-11 12:36:52 +00001950 private ConfigurationEvent event;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001951
Felix Meschbergere94b1572012-07-14 11:59:29 +00001952 private FireConfigurationEvent( final ServiceTracker listenerTracker, final int type, final String pid, final String factoryPid)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001953 {
1954 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001955 this.pid = pid;
1956 this.factoryPid = factoryPid;
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001957
Felix Meschbergere94b1572012-07-14 11:59:29 +00001958 final ServiceReference[] srs = listenerTracker.getServiceReferences();
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001959 if ( srs == null || srs.length == 0 )
1960 {
1961 this.listenerReferences = null;
1962 this.listeners = null;
1963 this.listenerProvider = null;
1964 }
1965 else
1966 {
1967 this.listenerReferences = srs;
1968 this.listeners = new ConfigurationListener[srs.length];
1969 this.listenerProvider = new Bundle[srs.length];
1970 for ( int i = 0; i < srs.length; i++ )
1971 {
Felix Meschbergere94b1572012-07-14 11:59:29 +00001972 this.listeners[i] = ( ConfigurationListener ) listenerTracker.getService( srs[i] );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001973 this.listenerProvider[i] = srs[i].getBundle();
1974 }
1975 }
1976 }
1977
1978
1979 boolean hasConfigurationEventListeners()
1980 {
1981 return this.listenerReferences != null;
1982 }
1983
1984
1985 String getTypeName()
1986 {
1987 switch ( type )
1988 {
1989 case ConfigurationEvent.CM_DELETED:
1990 return "CM_DELETED";
1991 case ConfigurationEvent.CM_UPDATED:
1992 return "CM_UPDATED";
Felix Meschberger007c50e2011-10-20 12:39:38 +00001993 case ConfigurationEvent.CM_LOCATION_CHANGED:
1994 return "CM_LOCATION_CHANGED";
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001995 default:
1996 return "<UNKNOWN(" + type + ")>";
1997 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001998 }
1999
2000
2001 public void run()
2002 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00002003 for ( int i = 0; i < listeners.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002004 {
Felix Meschberger0770cad2012-06-11 12:36:52 +00002005 sendEvent( i );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002006 }
2007 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00002008
Felix Meschberger0770cad2012-06-11 12:36:52 +00002009
Felix Meschberger432e3872008-03-07 14:58:57 +00002010 public String toString()
2011 {
2012 return "Fire ConfigurationEvent: pid=" + pid;
2013 }
Felix Meschberger0770cad2012-06-11 12:36:52 +00002014
2015
2016 private ConfigurationEvent getConfigurationEvent()
2017 {
2018 if ( event == null )
2019 {
2020 this.event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
2021 }
2022 return event;
2023 }
2024
2025
2026 private void sendEvent( final int serviceIndex )
2027 {
2028 if ( listenerProvider[serviceIndex].getState() == Bundle.ACTIVE && this.listeners[serviceIndex] != null )
2029 {
2030 log( LogService.LOG_DEBUG, "Sending {0} event for {1} to {2}", new Object[]
2031 { getTypeName(), pid, ConfigurationManager.toString( listenerReferences[serviceIndex] ) } );
2032
2033 try
2034 {
2035 listeners[serviceIndex].configurationEvent( getConfigurationEvent() );
2036 }
2037 catch ( Throwable t )
2038 {
2039 log( LogService.LOG_ERROR, "Unexpected problem delivering configuration event to {0}", new Object[]
2040 { ConfigurationManager.toString( listenerReferences[serviceIndex] ), t } );
2041 }
2042 finally
2043 {
2044 this.listeners[serviceIndex] = null;
2045 }
2046 }
2047 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002048 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002049}
Felix Meschberger273985f2012-07-05 12:28:06 +00002050