blob: e9e4620814abc7bbbae0bf039f749a29e1515a3e [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
Carsten Ziegeler014cca62015-05-11 18:17:28 +0000705 if ( configList.size() == 0 )
706 {
707 return null;
708 }
Felix Meschberger8faceff2007-07-04 07:19:48 +0000709 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000710 .size()] );
711 }
712
713
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000714 void deleted( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000715 {
716 // remove the configuration from the cache
717 removeConfiguration( config );
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000718 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000719 updateThread.schedule( new DeleteConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000720 log( LogService.LOG_DEBUG, "DeleteConfiguration({0}) scheduled", new Object[]
721 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000722 }
723
724
Felix Meschbergerce67d732009-08-20 06:26:35 +0000725 void updated( ConfigurationImpl config, boolean fireEvent )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000726 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000727 if ( fireEvent )
728 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000729 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000730 }
731 updateThread.schedule( new UpdateConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000732 log( LogService.LOG_DEBUG, "UpdateConfiguration({0}) scheduled", new Object[]
733 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000734 }
735
736
Felix Meschberger007c50e2011-10-20 12:39:38 +0000737 void locationChanged( ConfigurationImpl config, String oldLocation )
738 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000739 fireConfigurationEvent( ConfigurationEvent.CM_LOCATION_CHANGED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger35658d52011-10-20 21:43:58 +0000740 if ( oldLocation != null && !config.isNew() )
Felix Meschberger007c50e2011-10-20 12:39:38 +0000741 {
742 updateThread.schedule( new LocationChanged( config, oldLocation ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000743 log( LogService.LOG_DEBUG, "LocationChanged({0}, {1}=>{2}) scheduled", new Object[]
744 { config.getPid(), oldLocation, config.getBundleLocation() } );
Felix Meschberger35658d52011-10-20 21:43:58 +0000745 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000746 else
Felix Meschberger35658d52011-10-20 21:43:58 +0000747 {
748 log( LogService.LOG_DEBUG,
Felix Meschberger4f269292011-10-21 13:52:31 +0000749 "LocationChanged not scheduled for {0} (old location is null or configuration is new)", new Object[]
750 { config.getPid() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000751 }
752 }
753
754
Felix Meschberger66423332007-08-22 08:46:34 +0000755 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000756 {
Felix Meschbergere94b1572012-07-14 11:59:29 +0000757 // prevent event senders
758 FireConfigurationEvent asyncSender = new FireConfigurationEvent( this.configurationListenerTracker, type, pid,
759 factoryPid );
760 FireConfigurationEvent syncSender = new FireConfigurationEvent( this.syncConfigurationListenerTracker, type,
761 pid, factoryPid );
762
763 // send synchronous events
764 if ( syncSender.hasConfigurationEventListeners() )
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000765 {
Felix Meschbergere94b1572012-07-14 11:59:29 +0000766 syncSender.run();
767 }
768 else
769 {
770 log( LogService.LOG_DEBUG, "No SynchronousConfigurationListeners to send {0} event to.", new Object[]
771 { syncSender.getTypeName() } );
772 }
773
774 // schedule asynchronous events
775 if ( asyncSender.hasConfigurationEventListeners() )
776 {
777 eventThread.schedule( asyncSender );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000778 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000779 else
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000780 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000781 log( LogService.LOG_DEBUG, "No ConfigurationListeners to send {0} event to.", new Object[]
Felix Meschbergere94b1572012-07-14 11:59:29 +0000782 { asyncSender.getTypeName() } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000783 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000784 }
785
786
787 // ---------- BundleListener -----------------------------------------------
788
789 public void bundleChanged( BundleEvent event )
790 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000791 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000792 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000793 final String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000794
Felix Meschberger6a698df2009-08-16 18:38:46 +0000795 // we only reset dynamic bindings, which are only present in
796 // cached configurations, hence only consider cached configs here
797 final ConfigurationImpl[] configs = getCachedConfigurations();
798 for ( int i = 0; i < configs.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000799 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000800 final ConfigurationImpl cfg = configs[i];
Felix Meschberger41cce522009-08-19 05:54:40 +0000801 if ( location.equals( cfg.getDynamicBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000802 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000803 cfg.setDynamicBundleLocation( null, true );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000804 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000805 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000806 }
807 }
808
809
810 // ---------- internal -----------------------------------------------------
811
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000812 private CachingPersistenceManagerProxy[] getPersistenceManagers()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000813 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000814 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
815 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000816 {
817
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000818 List pmList = new ArrayList();
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000819 CachingPersistenceManagerProxy[] pm;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000820
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000821 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
822 if ( refs == null || refs.length == 0 )
823 {
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000824 pm = new CachingPersistenceManagerProxy[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000825 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000826 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000827 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000828 // sort the references according to the cmRanking property
Felix Meschberger007c50e2011-10-20 12:39:38 +0000829 if ( refs.length > 1 )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000830 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000831 Arrays.sort( refs, RankingComparator.SRV_RANKING );
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000832 }
833
834 // create the service array from the sorted set of referenecs
Felix Meschberger007c50e2011-10-20 12:39:38 +0000835 for ( int i = 0; i < refs.length; i++ )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000836 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000837 Object service = persistenceManagerTracker.getService( refs[i] );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000838 if ( service != null )
839 {
Felix Meschbergera86cdfc2010-08-25 09:32:36 +0000840 pmList.add( new CachingPersistenceManagerProxy( ( PersistenceManager ) service ) );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000841 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000842 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000843
Guillaume Nodet39f688d2015-03-02 17:21:45 +0000844 pm = ( CachingPersistenceManagerProxy[] ) pmList.toArray( new CachingPersistenceManagerProxy[pmList.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000845 }
846
Felix Meschbergerf748bfb2013-09-25 13:54:40 +0000847 pmtCount = currentPmtCount;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000848 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000849 }
850
851 return persistenceManagers;
852 }
853
854
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000855 private ServiceReference getServiceReference()
856 {
857 ServiceRegistration reg = configurationAdminRegistration;
Felix Meschberger0770cad2012-06-11 12:36:52 +0000858 if (reg != null) {
859 return reg.getReference();
860 }
861
862 // probably called for firing an event during service registration
863 // since we didn't get the service registration yet we use the
864 // service registry to get our service reference
865 BundleContext context = bundleContext;
866 if ( context != null )
867 {
868 try
869 {
870 ServiceReference[] refs = context.getServiceReferences( ConfigurationAdmin.class.getName(), null );
871 if ( refs != null )
872 {
873 for ( int i = 0; i < refs.length; i++ )
874 {
875 if ( refs[i].getBundle().getBundleId() == context.getBundle().getBundleId() )
876 {
877 return refs[i];
878 }
879 }
880 }
881 }
882 catch ( InvalidSyntaxException e )
883 {
884 // unexpected since there is no filter
885 }
886 }
887
888 // service references
889 return null;
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000890 }
891
892
Felix Meschberger05d89e12011-11-03 23:37:10 +0000893 /**
894 * Configures the ManagedService and returns the service.pid
895 * service property as a String[], which may be <code>null</code> if
896 * the ManagedService does not have such a property.
897 */
Felix Meschberger05d89e12011-11-03 23:37:10 +0000898 /**
899 * Configures the ManagedServiceFactory and returns the service.pid
900 * service property as a String[], which may be <code>null</code> if
901 * the ManagedServiceFactory does not have such a property.
902 */
Felix Meschberger382a19b2012-07-03 09:45:14 +0000903 /**
904 * Schedules the configuration of the referenced service with
905 * configuration for the given PID.
906 *
Felix Meschberger273985f2012-07-05 12:28:06 +0000907 * @param pid The list of service PID of the configurations to be
908 * provided to the referenced service.
Felix Meschberger382a19b2012-07-03 09:45:14 +0000909 * @param sr The <code>ServiceReference</code> to the service
910 * to be configured.
911 * @param factory <code>true</code> If the service is considered to
912 * be a <code>ManagedServiceFactory</code>. Otherwise the service
913 * is considered to be a <code>ManagedService</code>.
914 */
Felix Meschberger3cbf4652012-10-18 06:49:39 +0000915 public void configure( String[] pid, ServiceReference sr, final boolean factory, final ConfigurationMap<?> configs )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000916 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000917 if ( this.isLogEnabled( LogService.LOG_DEBUG ) )
918 {
919 this.log( LogService.LOG_DEBUG, "configure(ManagedService {0})", new Object[]
920 { toString( sr ) } );
921 }
922
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000923 Runnable r;
924 if ( factory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000925 {
Felix Meschberger3cbf4652012-10-18 06:49:39 +0000926 r = new ManagedServiceFactoryUpdate( pid, sr, configs );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000927 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000928 else
929 {
Felix Meschberger3cbf4652012-10-18 06:49:39 +0000930 r = new ManagedServiceUpdate( pid, sr, configs );
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000931 }
932 updateThread.schedule( r );
933 log( LogService.LOG_DEBUG, "[{0}] scheduled", new Object[]
934 { r } );
Felix Meschberger851c6412009-08-16 18:43:26 +0000935 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000936
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000937
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000938 /**
939 * Factory method to create a new configuration object. The configuration
940 * object returned is not stored in configuration cache and only persisted
941 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000942 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000943 * @param pid
944 * The PID of the new configuration object. Must not be
945 * <code>null</code>.
946 * @param factoryPid
947 * The factory PID of the new configuration. Not
Felix Meschberger6a698df2009-08-16 18:38:46 +0000948 * <code>null</code> if the new configuration object belongs to a
949 * factory. The configuration object will not be persisted if
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000950 * this parameter is not <code>null</code>.
951 * @param bundleLocation
952 * The bundle location of the bundle to which the configuration
Felix Meschberger6a698df2009-08-16 18:38:46 +0000953 * belongs or <code>null</code> if the configuration is not bound
954 * yet.
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000955 * @return The new configuration object
956 * @throws IOException
957 * May be thrown if an error occurrs persisting the new
958 * configuration object.
959 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000960 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000961 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000962 log( LogService.LOG_DEBUG, "createConfiguration({0}, {1}, {2})", new Object[]
963 { pid, factoryPid, bundleLocation } );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000964 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000965 }
966
967
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000968 /**
969 * Returns a list of {@link Factory} instances according to the
970 * Configuration Admin 1.5 specification for targeted PIDs (Section
971 * 104.3.2)
972 *
973 * @param rawFactoryPid The raw factory PID without any targetting.
974 * @param target The <code>ServiceReference</code> of the service to
975 * be supplied with targeted configuration.
976 * @return A list of {@link Factory} instances as listed above. This
977 * list will always at least include an instance for the
978 * <code>rawFactoryPid</code>. Other instances are only included
979 * if existing.
980 * @throws IOException If an error occurrs reading any of the
981 * {@link Factory} instances from persistence
982 */
983 List<Factory> getTargetedFactories( final String rawFactoryPid, final ServiceReference target ) throws IOException
984 {
985 LinkedList<Factory> factories = new LinkedList<Factory>();
986
987 final Bundle serviceBundle = target.getBundle();
988 if ( serviceBundle != null )
989 {
990 // for pre-1.5 API compatibility
991 final StringBuffer targetedPid = new StringBuffer( rawFactoryPid );
992 factories.add( getOrCreateFactory( targetedPid.toString() ) );
993
994 targetedPid.append( '|' ).append( serviceBundle.getSymbolicName() );
995 Factory f = getFactory( targetedPid.toString() );
996 if ( f != null )
997 {
998 factories.add( 0, f );
999 }
1000
1001 targetedPid.append( '|' ).append( TargetedPID.getBundleVersion( serviceBundle ) );
1002 f = getFactory( targetedPid.toString() );
1003 if ( f != null )
1004 {
1005 factories.add( 0, f );
1006 }
1007
1008 targetedPid.append( '|' ).append( serviceBundle.getLocation() );
1009 f = getFactory( targetedPid.toString() );
1010 if ( f != null )
1011 {
1012 factories.add( 0, f );
1013 }
1014 }
1015
1016 return factories;
1017 }
1018
1019
1020 /**
1021 * Gets the factory with the exact identifier from the cached or from
1022 * the persistence managers. If no factory exists already one is
1023 * created and cached.
1024 *
1025 * @param factoryPid The PID of the {@link Factory} to return
1026 * @return The existing or newly created {@link Factory}
1027 * @throws IOException If an error occurrs reading the factory from
1028 * a {@link PersistenceManager}
1029 */
1030 Factory getOrCreateFactory( String factoryPid ) throws IOException
1031 {
1032 Factory factory = getFactory( factoryPid );
1033 if ( factory != null )
1034 {
1035 return factory;
1036 }
1037
1038 return createFactory( factoryPid );
1039 }
1040
1041
1042 /**
1043 * Gets the factory with the exact identifier from the cached or from
1044 * the persistence managers. If no factory exists <code>null</code>
1045 * is returned.
1046 *
1047 * @param factoryPid The PID of the {@link Factory} to return
1048 * @return The existing {@link Factory} or <code>null</code>
1049 * @throws IOException If an error occurrs reading the factory from
1050 * a {@link PersistenceManager}
1051 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001052 Factory getFactory( String factoryPid ) throws IOException
1053 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001054 // check for cached factory
Felix Meschbergerf4631322008-03-10 12:32:35 +00001055 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001056 if ( factory != null )
1057 {
1058 return factory;
1059 }
1060
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001061 // try to load factory from persistence
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001062 PersistenceManager[] pmList = getPersistenceManagers();
1063 for ( int i = 0; i < pmList.length; i++ )
1064 {
1065 if ( Factory.exists( pmList[i], factoryPid ) )
1066 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +00001067 factory = Factory.load( this, pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001068 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001069 return factory;
1070 }
1071 }
1072
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001073 // no existing factory
1074 return null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001075 }
1076
1077
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001078 /**
1079 * Creates a new factory with the given <code>factoryPid</code>.
1080 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001081 Factory createFactory( String factoryPid )
1082 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +00001083 Factory factory = new Factory( this, getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001084 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001085 return factory;
1086 }
1087
1088
Felix Meschberger2941ef92007-08-20 13:15:16 +00001089 /**
1090 * Calls the registered configuration plugins on the given configuration
Felix Meschberger273985f2012-07-05 12:28:06 +00001091 * properties from the given configuration object.
1092 * <p>
1093 * The plugins to be called are selected as <code>ConfigurationPlugin</code>
1094 * services registered with a <code>cm.target</code> property set to
1095 * <code>*</code> or the factory PID of the configuration (for factory
1096 * configurations) or the PID of the configuration (for non-factory
1097 * configurations).
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001098 *
Felix Meschberger41cce522009-08-19 05:54:40 +00001099 * @param props The configuraiton properties run through the registered
Felix Meschberger273985f2012-07-05 12:28:06 +00001100 * ConfigurationPlugin services. This must not be
1101 * <code>null</code>.
Felix Meschberger2941ef92007-08-20 13:15:16 +00001102 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001103 * is to be updated with configuration
Felix Meschberger273985f2012-07-05 12:28:06 +00001104 * @param configPid The PID of the configuration object whose properties
1105 * are to be augmented
1106 * @param factoryPid the factory PID of the configuration object whose
1107 * properties are to be augmented. This is non-<code>null</code>
1108 * only for a factory configuration.
Felix Meschberger2941ef92007-08-20 13:15:16 +00001109 */
Felix Meschberger273985f2012-07-05 12:28:06 +00001110 public void callPlugins( final Dictionary props, final ServiceReference sr, final String configPid,
1111 final String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001112 {
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001113 ServiceReference[] plugins = null;
1114 try
1115 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001116 final String targetPid = (factoryPid == null) ? configPid : factoryPid;
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001117 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001118 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001119 }
1120 catch ( InvalidSyntaxException ise )
1121 {
1122 // no filter, no exception ...
1123 }
1124
1125 // abort early if there are no plugins
1126 if ( plugins == null || plugins.length == 0 )
1127 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001128 return;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001129 }
1130
1131 // sort the plugins by their service.cmRanking
Felix Meschberger007c50e2011-10-20 12:39:38 +00001132 if ( plugins.length > 1 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001133 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001134 Arrays.sort( plugins, RankingComparator.CM_RANKING );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001135 }
1136
1137 // call the plugins in order
Felix Meschberger007c50e2011-10-20 12:39:38 +00001138 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001139 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001140 ServiceReference pluginRef = plugins[i];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001141 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001142 if ( plugin != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001143 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001144 try
1145 {
1146 plugin.modifyConfiguration( sr, props );
1147 }
1148 catch ( Throwable t )
1149 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001150 log( LogService.LOG_ERROR, "Unexpected problem calling configuration plugin {0}", new Object[]
1151 { toString( pluginRef ), t } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001152 }
1153 finally
1154 {
1155 // ensure ungetting the plugin
1156 bundleContext.ungetService( pluginRef );
1157 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001158 ConfigurationImpl.setAutoProperties( props, configPid, factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001159 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001160 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001161 }
1162
1163
1164 /**
1165 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001166 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001167 * @param factoryPid
1168 * @return
1169 */
1170 private static String createPid( String factoryPid )
1171 {
Felix Meschberger417f66c2011-02-04 11:25:23 +00001172 Random ng = numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001173 if ( ng == null )
1174 {
Felix Meschberger417f66c2011-02-04 11:25:23 +00001175 // FELIX-2771 Secure Random not available on Mika
1176 try
1177 {
1178 ng = new SecureRandom();
1179 }
1180 catch ( Throwable t )
1181 {
1182 // fall back to Random
1183 ng = new Random();
1184 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001185 }
1186
1187 byte[] randomBytes = new byte[16];
1188 ng.nextBytes( randomBytes );
1189 randomBytes[6] &= 0x0f; /* clear version */
1190 randomBytes[6] |= 0x40; /* set to version 4 */
1191 randomBytes[8] &= 0x3f; /* clear variant */
1192 randomBytes[8] |= 0x80; /* set to IETF variant */
1193
1194 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
1195
1196 // prefix the new pid with the factory pid
1197 buf.append( factoryPid ).append( "." );
1198
1199 // serialize the UUID into the buffer
1200 for ( int i = 0; i < randomBytes.length; i++ )
1201 {
1202
1203 if ( i == 4 || i == 6 || i == 8 || i == 10 )
1204 {
1205 buf.append( '-' );
1206 }
1207
1208 int val = randomBytes[i] & 0xff;
1209 buf.append( Integer.toHexString( val >> 4 ) );
1210 buf.append( Integer.toHexString( val & 0xf ) );
1211 }
1212
1213 return buf.toString();
1214 }
1215
1216
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001217 public boolean isLogEnabled( int level )
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001218 {
1219 return level <= logLevel;
1220 }
1221
1222
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001223 public void log( int level, String format, Object[] args )
Felix Meschberger4f269292011-10-21 13:52:31 +00001224 {
1225 if ( isLogEnabled( level ) )
1226 {
1227 Throwable throwable = null;
1228 String message = format;
1229
1230 if ( args != null && args.length > 0 )
1231 {
1232 if ( args[args.length - 1] instanceof Throwable )
1233 {
1234 throwable = ( Throwable ) args[args.length - 1];
1235 }
1236 message = MessageFormat.format( format, args );
1237 }
1238
1239 log( level, message, throwable );
1240 }
1241 }
1242
1243
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001244 public void log( int level, String message, Throwable t )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001245 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001246 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +00001247 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001248 if ( log != null )
1249 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +00001250 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001251 return;
1252 }
1253
Felix Meschberger08282c32009-01-28 07:01:55 +00001254 // Otherwise only log if more serious than the configured level
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001255 if ( isLogEnabled( level ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001256 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001257 String code;
1258 switch ( level )
1259 {
1260 case LogService.LOG_INFO:
1261 code = "*INFO *";
1262 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001263
Felix Meschberger08282c32009-01-28 07:01:55 +00001264 case LogService.LOG_WARNING:
1265 code = "*WARN *";
1266 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001267
Felix Meschberger08282c32009-01-28 07:01:55 +00001268 case LogService.LOG_ERROR:
1269 code = "*ERROR*";
1270 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001271
Felix Meschberger08282c32009-01-28 07:01:55 +00001272 case LogService.LOG_DEBUG:
1273 default:
1274 code = "*DEBUG*";
1275 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001276
Felix Meschberger08282c32009-01-28 07:01:55 +00001277 System.err.println( code + " " + message );
1278 if ( t != null )
1279 {
1280 t.printStackTrace( System.err );
1281 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001282 }
1283 }
1284
Felix Meschberger851c6412009-08-16 18:43:26 +00001285
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001286 public static String toString( ServiceReference ref )
Felix Meschberger41cce522009-08-19 05:54:40 +00001287 {
1288 String[] ocs = ( String[] ) ref.getProperty( "objectClass" );
Felix Meschberger382a19b2012-07-03 09:45:14 +00001289 StringBuffer buf = new StringBuffer( "[" );
Felix Meschberger41cce522009-08-19 05:54:40 +00001290 for ( int i = 0; i < ocs.length; i++ )
1291 {
Felix Meschberger382a19b2012-07-03 09:45:14 +00001292 buf.append( ocs[i] );
Felix Meschberger41cce522009-08-19 05:54:40 +00001293 if ( i < ocs.length - 1 )
Felix Meschberger382a19b2012-07-03 09:45:14 +00001294 buf.append( ", " );
Felix Meschberger41cce522009-08-19 05:54:40 +00001295 }
1296
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001297 buf.append( ", id=" ).append( ref.getProperty( Constants.SERVICE_ID ) );
1298
1299 Bundle provider = ref.getBundle();
1300 if ( provider != null )
1301 {
1302 buf.append( ", bundle=" ).append( provider.getBundleId() );
Felix Meschberger0135b322011-11-16 12:30:22 +00001303 buf.append( '/' ).append( provider.getLocation() );
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001304 }
1305 else
1306 {
1307 buf.append( ", unregistered" );
1308 }
1309
1310 buf.append( "]" );
1311 return buf.toString();
Felix Meschberger41cce522009-08-19 05:54:40 +00001312 }
1313
Felix Meschbergerce67d732009-08-20 06:26:35 +00001314
Felix Meschberger007c50e2011-10-20 12:39:38 +00001315 /**
1316 * Checks whether the bundle is allowed to receive the configuration
1317 * with the given location binding.
1318 * <p>
1319 * This method implements the logic defined CM 1.4 / 104.4.1:
1320 * <ul>
1321 * <li>If the location is <code>null</code> (the configuration is not
1322 * bound yet), assume the bundle is allowed</li>
1323 * <li>If the location is a single location (no leading "?"), require
1324 * the bundle's location to match</li>
1325 * <li>If the location is a multi-location (leading "?"), assume the
1326 * bundle is allowed if there is no security manager. If there is a
1327 * security manager, check whether the bundle has "target" permission
1328 * on this location.</li>
1329 * </ul>
1330 */
1331 boolean canReceive( final Bundle bundle, final String location )
1332 {
1333 if ( location == null )
1334 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001335 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration=(unbound)", new Object[]
Felix Meschberger61207232011-11-17 10:06:45 +00001336 { bundle.getLocation() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001337 return true;
1338 }
1339 else if ( location.startsWith( "?" ) )
1340 {
1341 // multi-location
1342 if ( System.getSecurityManager() != null )
1343 {
Felix Meschberger61207232011-11-17 10:06:45 +00001344 final boolean hasPermission = bundle.hasPermission( new ConfigurationPermission( location,
1345 ConfigurationPermission.TARGET ) );
1346 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2} (SecurityManager check)",
1347 new Object[]
1348 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1349 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001350 }
Felix Meschberger61207232011-11-17 10:06:45 +00001351
1352 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration={1} (no SecurityManager)",
1353 new Object[]
1354 { bundle.getLocation(), location } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001355 return true;
1356 }
1357 else
1358 {
1359 // single location, must match
Felix Meschberger61207232011-11-17 10:06:45 +00001360 final boolean hasPermission = location.equals( bundle.getLocation() );
1361 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2}", new Object[]
1362 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1363 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001364 }
1365 }
1366
Felix Meschberger61207232011-11-17 10:06:45 +00001367
Felix Meschberger007c50e2011-10-20 12:39:38 +00001368 // ---------- inner classes
1369
Felix Meschberger007c50e2011-10-20 12:39:38 +00001370 /**
1371 * The <code>ManagedServiceUpdate</code> updates a freshly registered
1372 * <code>ManagedService</code> with a specific configuration. If a
1373 * ManagedService is registered with multiple PIDs an instance of this
1374 * class is used for each registered PID.
1375 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001376 private class ManagedServiceUpdate implements Runnable
1377 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001378 private final String[] pids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001379
Felix Meschberger41cce522009-08-19 05:54:40 +00001380 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001381
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001382 private final ConfigurationMap<?> configs;
1383
1384
1385 ManagedServiceUpdate( String[] pids, ServiceReference sr, ConfigurationMap<?> configs )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001386 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001387 this.pids = pids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001388 this.sr = sr;
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001389 this.configs = configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001390 }
1391
1392
1393 public void run()
1394 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001395 for ( String pid : this.pids )
1396 {
1397 try
1398 {
1399 final ConfigurationImpl config = getTargetedConfiguration( pid, this.sr );
1400 provide( pid, config );
1401 }
1402 catch ( IOException ioe )
1403 {
1404 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1405 { pid, ioe } );
1406 }
1407 catch ( Exception e )
1408 {
1409 log( LogService.LOG_ERROR, "Unexpected problem providing configuration {0} to service {1}",
1410 new Object[]
1411 { pid, ConfigurationManager.toString( this.sr ), e } );
1412 }
1413 }
1414 }
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001415
Felix Meschberger273985f2012-07-05 12:28:06 +00001416
1417 private void provide(final String servicePid, final ConfigurationImpl config)
1418 {
1419 // check configuration
1420 final TargetedPID configPid;
1421 final Dictionary properties;
1422 final long revision;
Felix Meschberger41cce522009-08-19 05:54:40 +00001423 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001424 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001425 synchronized ( config )
Felix Meschberger41243192009-01-14 19:59:58 +00001426 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001427 configPid = config.getPid();
1428 properties = config.getProperties( true );
1429 revision = config.getRevision();
Felix Meschberger41243192009-01-14 19:59:58 +00001430 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001431 }
1432 else
1433 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001434 // 104.5.3 ManagedService.updated must be called with null
1435 // if no configuration is available
Felix Meschberger273985f2012-07-05 12:28:06 +00001436 configPid = new TargetedPID( servicePid );
Felix Meschberger41cce522009-08-19 05:54:40 +00001437 properties = null;
Felix Meschberger273985f2012-07-05 12:28:06 +00001438 revision = -1;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001439 }
1440
Felix Meschberger273985f2012-07-05 12:28:06 +00001441 log( LogService.LOG_DEBUG, "Updating service {0} with configuration {1}@{2}", new Object[]
1442 { servicePid, configPid, new Long( revision ) } );
1443
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001444 managedServiceTracker.provideConfiguration( sr, configPid, null, properties, revision, this.configs );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001445 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001446
Carsten Ziegeler014cca62015-05-11 18:17:28 +00001447 @Override
Felix Meschberger432e3872008-03-07 14:58:57 +00001448 public String toString()
1449 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001450 return "ManagedService Update: pid=" + Arrays.asList( pids );
Felix Meschberger432e3872008-03-07 14:58:57 +00001451 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001452 }
1453
Felix Meschberger007c50e2011-10-20 12:39:38 +00001454 /**
1455 * The <code>ManagedServiceFactoryUpdate</code> updates a freshly
1456 * registered <code>ManagedServiceFactory</code> with a specific
1457 * configuration. If a ManagedServiceFactory is registered with
1458 * multiple PIDs an instance of this class is used for each registered
1459 * PID.
1460 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001461 private class ManagedServiceFactoryUpdate implements Runnable
1462 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001463 private final String[] factoryPids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001464
Felix Meschberger41cce522009-08-19 05:54:40 +00001465 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001466
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001467 private final ConfigurationMap<?> configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001468
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001469
1470 ManagedServiceFactoryUpdate( String[] factoryPids, ServiceReference sr, final ConfigurationMap<?> configs )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001471 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001472 this.factoryPids = factoryPids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001473 this.sr = sr;
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001474 this.configs = configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001475 }
1476
1477
1478 public void run()
1479 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001480 for ( String factoryPid : this.factoryPids )
1481 {
1482
1483 List<Factory> factories = null;
1484 try
1485 {
1486 factories = getTargetedFactories( factoryPid, sr );
1487 for ( Factory factory : factories )
1488 {
1489 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
1490 {
1491 final String pid = ( String ) pi.next();
1492 ConfigurationImpl cfg;
1493 try
1494 {
1495 cfg = getConfiguration( pid );
1496 }
1497 catch ( IOException ioe )
1498 {
1499 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1500 { pid, ioe } );
1501 continue;
1502 }
1503
1504 // sanity check on the configuration
1505 if ( cfg == null )
1506 {
1507 log( LogService.LOG_ERROR,
1508 "Configuration {0} referred to by factory {1} does not exist", new Object[]
1509 { pid, factoryPid } );
1510 factory.removePID( pid );
1511 factory.storeSilently();
1512 continue;
1513 }
1514 else if ( cfg.isNew() )
1515 {
1516 // Configuration has just been created but not yet updated
1517 // we currently just ignore it and have the update mechanism
1518 // provide the configuration to the ManagedServiceFactory
1519 // As of FELIX-612 (not storing new factory configurations)
1520 // this should not happen. We keep this for added stability
1521 // but raise the logging level to error.
1522 log( LogService.LOG_ERROR, "Ignoring new configuration pid={0}", new Object[]
1523 { pid } );
1524 continue;
1525 }
1526
1527 /*
1528 * this code would catch targeted factory PIDs;
1529 * since this is not expected any way, we can
1530 * leave this out
1531 */
1532 /*
1533 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1534 {
1535 log( LogService.LOG_ERROR,
1536 "Configuration {0} referred to by factory {1} seems to belong to factory {2}",
1537 new Object[]
1538 { pid, factoryPid, cfg.getFactoryPid() } );
1539 factory.removePID( pid );
1540 factory.storeSilently();
1541 continue;
1542 }
1543 */
1544
1545 provide( factoryPid, cfg );
1546 }
1547 }
1548 }
1549 catch ( IOException ioe )
1550 {
1551 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID {0}", new Object[]
1552 { factoryPid, ioe } );
1553 }
1554 }
1555 }
1556
1557
1558 private void provide(final String factoryPid, final ConfigurationImpl config) {
1559
1560 final Dictionary rawProperties;
1561 final long revision;
1562 synchronized ( config )
1563 {
1564 rawProperties = config.getProperties( true );
1565 revision = config.getRevision();
1566 }
1567
1568 log( LogService.LOG_DEBUG, "Updating service {0} with configuration {1}/{2}@{3}", new Object[]
1569 { factoryPid, config.getFactoryPid(), config.getPid(), new Long( revision ) } );
1570
1571 // CM 1.4 / 104.13.2.1
1572 final Bundle serviceBundle = this.sr.getBundle();
Felix Meschberger41243192009-01-14 19:59:58 +00001573 if ( serviceBundle == null )
1574 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001575 log(
1576 LogService.LOG_INFO,
1577 "ManagedServiceFactory for factory PID {0} seems to already have been unregistered, not updating with factory",
1578 new Object[]
1579 { factoryPid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001580 return;
1581 }
1582
Felix Meschberger273985f2012-07-05 12:28:06 +00001583 if ( !canReceive( serviceBundle, config.getBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001584 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001585 log( LogService.LOG_ERROR,
1586 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001587 new Object[]
Felix Meschberger273985f2012-07-05 12:28:06 +00001588 { config.getPid(), ConfigurationManager.toString( sr ), config.getBundleLocation() } );
1589
1590 // no service, really, bail out
1591 return;
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001592 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001593
1594 // 104.4.2 Dynamic Binding
1595 config.tryBindLocation( serviceBundle.getLocation() );
1596
1597 // update the service with the configuration (if non-null)
1598 if ( rawProperties != null )
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001599 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001600 log( LogService.LOG_DEBUG, "{0}: Updating configuration pid={1}", new Object[]
1601 { ConfigurationManager.toString( sr ), config.getPid() } );
1602 managedServiceFactoryTracker.provideConfiguration( sr, config.getPid(), config.getFactoryPid(),
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001603 rawProperties, revision, this.configs );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001604 }
1605 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001606
1607
Carsten Ziegeler014cca62015-05-11 18:17:28 +00001608 @Override
Felix Meschberger432e3872008-03-07 14:58:57 +00001609 public String toString()
1610 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001611 return "ManagedServiceFactory Update: factoryPid=" + Arrays.asList( this.factoryPids );
Felix Meschberger432e3872008-03-07 14:58:57 +00001612 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001613 }
1614
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001615 private abstract class ConfigurationProvider<T> implements Runnable
1616 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001617
1618 protected final ConfigurationImpl config;
1619 protected final long revision;
1620 protected final Dictionary<String, ?> properties;
Felix Meschbergerfffde292012-11-18 18:02:20 +00001621 private BaseTracker<T> helper;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001622
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001623
1624 protected ConfigurationProvider( final ConfigurationImpl config )
1625 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001626 synchronized ( config )
1627 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001628 this.config = config;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001629 this.revision = config.getRevision();
1630 this.properties = config.getProperties( true );
1631 }
1632 }
1633
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001634
1635 protected TargetedPID getTargetedServicePid()
1636 {
1637 final TargetedPID factoryPid = this.config.getFactoryPid();
1638 if ( factoryPid != null )
1639 {
1640 return factoryPid;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001641 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001642 return this.config.getPid();
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001643 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001644
1645
Felix Meschbergerfffde292012-11-18 18:02:20 +00001646 protected BaseTracker<T> getHelper()
1647 {
1648 if ( this.helper == null )
1649 {
1650 this.helper = ( BaseTracker<T> ) ( ( this.config.getFactoryPid() == null ) ? ConfigurationManager.this.managedServiceTracker
1651 : ConfigurationManager.this.managedServiceFactoryTracker );
1652 }
1653 return this.helper;
1654 }
1655
1656
Felix Meschberger273985f2012-07-05 12:28:06 +00001657 protected boolean provideReplacement( ServiceReference<T> sr )
1658 {
1659 if ( this.config.getFactoryPid() == null )
1660 {
1661 try
1662 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001663 final String configPidString = this.getHelper().getServicePid( sr, this.config.getPid() );
Pierre De Rop10c313c2014-02-03 15:22:04 +00001664 if (configPidString == null) {
1665 return false; // The managed service is not registered anymore in the OSGi service registry.
1666 }
Felix Meschberger1ff5c532012-07-08 18:23:08 +00001667 final ConfigurationImpl rc = getTargetedConfiguration( configPidString, sr );
Felix Meschberger273985f2012-07-05 12:28:06 +00001668 if ( rc != null )
1669 {
1670 final TargetedPID configPid;
1671 final Dictionary properties;
1672 final long revision;
Felix Meschbergercd5195f2012-07-05 17:17:45 +00001673 synchronized ( rc )
Felix Meschberger273985f2012-07-05 12:28:06 +00001674 {
Felix Meschbergercd5195f2012-07-05 17:17:45 +00001675 configPid = rc.getPid();
1676 properties = rc.getProperties( true );
1677 revision = rc.getRevision();
Felix Meschberger273985f2012-07-05 12:28:06 +00001678 }
1679
Felix Meschbergerfffde292012-11-18 18:02:20 +00001680 this.getHelper().provideConfiguration( sr, configPid, null, properties, -revision, null );
Felix Meschberger273985f2012-07-05 12:28:06 +00001681
1682 return true;
1683 }
1684 }
1685 catch ( IOException ioe )
1686 {
1687 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1688 { this.config.getPid(), ioe } );
1689 }
1690 catch ( Exception e )
1691 {
1692 log( LogService.LOG_ERROR, "Unexpected problem providing configuration {0} to service {1}",
1693 new Object[]
1694 { this.config.getPid(), ConfigurationManager.toString( sr ), e } );
1695 }
1696 }
1697
1698 // factory or no replacement available
1699 return false;
1700 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001701 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001702
1703 /**
1704 * The <code>UpdateConfiguration</code> is used to update
1705 * <code>ManagedService[Factory]</code> services with the configuration
1706 * they are subscribed to. This may cause the configuration to be
1707 * supplied to multiple services.
1708 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001709 private class UpdateConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001710 {
1711
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001712 UpdateConfiguration( final ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001713 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001714 super( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001715 }
1716
1717
1718 public void run()
1719 {
Felix Meschberger61207232011-11-17 10:06:45 +00001720 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1721 { config.getPid(), new Long( revision ) } );
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001722
Felix Meschbergerfffde292012-11-18 18:02:20 +00001723 final List<ServiceReference<?>> srList = this.getHelper().getServices( getTargetedServicePid() );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001724 if ( !srList.isEmpty() )
Felix Meschberger41cce522009-08-19 05:54:40 +00001725 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001726 // optionally bind dynamically to the first service
Pierre De Rop10c313c2014-02-03 15:22:04 +00001727 Bundle bundle = srList.get(0).getBundle();
1728 if (bundle == null) {
1729 log( LogService.LOG_DEBUG,
1730 "Service {0} seems to be unregistered concurrently (not providing configuration)",
1731 new Object[]
1732 { ConfigurationManager.toString( srList.get(0) ) } );
1733 return;
1734 }
1735 config.tryBindLocation( bundle.getLocation() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001736
1737 final String configBundleLocation = config.getBundleLocation();
1738
1739 // provide configuration to all services from the
1740 // correct bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001741 for (ServiceReference<?> ref : srList)
Felix Meschberger41cce522009-08-19 05:54:40 +00001742 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001743 final Bundle refBundle = ref.getBundle();
1744 if ( refBundle == null )
Felix Meschberger41cce522009-08-19 05:54:40 +00001745 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001746 log( LogService.LOG_DEBUG,
1747 "Service {0} seems to be unregistered concurrently (not providing configuration)",
1748 new Object[]
1749 { ConfigurationManager.toString( ref ) } );
1750 }
1751 else if ( canReceive( refBundle, configBundleLocation ) )
1752 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001753 this.getHelper().provideConfiguration( ref, this.config.getPid(), this.config.getFactoryPid(),
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001754 this.properties, this.revision, null );
Felix Meschberger2444da62011-11-17 11:17:50 +00001755 }
1756 else
1757 {
1758 // CM 1.4 / 104.13.2.2
Felix Meschberger4f269292011-10-21 13:52:31 +00001759 log( LogService.LOG_ERROR,
1760 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1761 new Object[]
1762 { config.getPid(), ConfigurationManager.toString( ref ), configBundleLocation } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001763 }
1764
Felix Meschberger41cce522009-08-19 05:54:40 +00001765 }
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001766 }
Felix Meschberger137ee722011-11-16 09:51:59 +00001767 else if ( isLogEnabled( LogService.LOG_DEBUG ) )
1768 {
Felix Meschberger1ee888d2011-11-16 12:42:57 +00001769 log( LogService.LOG_DEBUG, "No ManagedService[Factory] registered for updates to configuration {0}",
Felix Meschberger137ee722011-11-16 09:51:59 +00001770 new Object[]
1771 { config.getPid() } );
1772 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001773 }
1774
1775
Carsten Ziegeler014cca62015-05-11 18:17:28 +00001776 @Override
Felix Meschberger432e3872008-03-07 14:58:57 +00001777 public String toString()
1778 {
1779 return "Update: pid=" + config.getPid();
1780 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001781 }
1782
Felix Meschberger007c50e2011-10-20 12:39:38 +00001783
1784 /**
1785 * The <code>DeleteConfiguration</code> class is used to inform
1786 * <code>ManagedService[Factory]</code> services of a configuration
1787 * being deleted.
1788 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001789 private class DeleteConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001790 {
Felix Meschberger66423332007-08-22 08:46:34 +00001791
Felix Meschbergerc12db8c2009-08-19 06:43:59 +00001792 private final String configLocation;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001793
1794
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001795 DeleteConfiguration( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001796 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001797 /*
1798 * NOTE: We keep the configuration because it might be cleared just
1799 * after calling this method. The pid and factoryPid fields are
1800 * final and cannot be reset.
1801 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001802 super(config);
Felix Meschberger007c50e2011-10-20 12:39:38 +00001803 this.configLocation = config.getBundleLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001804 }
1805
1806
1807 public void run()
1808 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001809 List<ServiceReference<?>> srList = this.getHelper().getServices( getTargetedServicePid() );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001810 if ( !srList.isEmpty() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001811 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001812 for (ServiceReference<?> sr : srList)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001813 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001814 final Bundle srBundle = sr.getBundle();
1815 if ( srBundle == null )
1816 {
1817 log( LogService.LOG_DEBUG,
1818 "Service {0} seems to be unregistered concurrently (not removing configuration)",
1819 new Object[]
1820 { ConfigurationManager.toString( sr ) } );
1821 }
1822 else if ( canReceive( srBundle, configLocation ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001823 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001824 // revoke configuration unless a replacement
1825 // configuration can be provided
1826 if ( !this.provideReplacement( sr ) )
1827 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001828 this.getHelper().removeConfiguration( sr, this.config.getPid(), this.config.getFactoryPid() );
Felix Meschberger273985f2012-07-05 12:28:06 +00001829 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001830 }
Felix Meschberger2444da62011-11-17 11:17:50 +00001831 else
1832 {
1833 // CM 1.4 / 104.13.2.2
1834 log( LogService.LOG_ERROR,
1835 "Cannot remove configuration {0} for {1}: No visibility to configuration bound to {2}",
1836 new Object[]
1837 { config.getPid(), ConfigurationManager.toString( sr ), configLocation } );
1838 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001839 }
1840 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001841
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001842 final TargetedPID factoryPid = config.getFactoryPid();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001843 if ( factoryPid != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001844 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001845 // remove the pid from the factory
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001846 final String pid = config.getPidString();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001847 try
1848 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001849 Factory factory = getOrCreateFactory( factoryPid.toString() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001850 factory.removePID( pid );
1851 factory.store();
1852 }
1853 catch ( IOException ioe )
1854 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001855 log( LogService.LOG_ERROR, "Failed removing {0} from the factory {1}", new Object[]
1856 { pid, factoryPid, ioe } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001857 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001858 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001859 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001860
Carsten Ziegeler014cca62015-05-11 18:17:28 +00001861 @Override
Felix Meschberger432e3872008-03-07 14:58:57 +00001862 public String toString()
1863 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001864 return "Delete: pid=" + config.getPid();
Felix Meschberger432e3872008-03-07 14:58:57 +00001865 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001866 }
1867
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001868 private class LocationChanged extends ConfigurationProvider
Felix Meschberger007c50e2011-10-20 12:39:38 +00001869 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001870 private final String oldLocation;
1871
1872
1873 LocationChanged( ConfigurationImpl config, String oldLocation )
1874 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001875 super( config );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001876 this.oldLocation = oldLocation;
1877 }
1878
1879
1880 public void run()
1881 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001882 List<ServiceReference<?>> srList = this.getHelper().getServices( getTargetedServicePid() );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001883 if ( !srList.isEmpty() )
Felix Meschberger007c50e2011-10-20 12:39:38 +00001884 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001885 for (final ServiceReference<?> sr : srList)
Felix Meschberger007c50e2011-10-20 12:39:38 +00001886 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001887 final Bundle srBundle = sr.getBundle();
1888 if ( srBundle == null )
1889 {
1890 log( LogService.LOG_DEBUG,
1891 "Service {0} seems to be unregistered concurrently (not processing)", new Object[]
1892 { ConfigurationManager.toString( sr ) } );
1893 continue;
1894 }
1895
1896 final boolean wasVisible = canReceive( srBundle, oldLocation );
1897 final boolean isVisible = canReceive( srBundle, config.getBundleLocation() );
1898
1899 // make sure the config is dynamically bound to the first
1900 // service if the config has been unbound causing this update
1901 if ( isVisible )
1902 {
1903 config.tryBindLocation( srBundle.getLocation() );
1904 }
1905
Felix Meschberger007c50e2011-10-20 12:39:38 +00001906 if ( wasVisible && !isVisible )
1907 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001908 // revoke configuration unless a replacement
1909 // configuration can be provided
1910 if ( !this.provideReplacement( sr ) )
1911 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001912 this.getHelper().removeConfiguration( sr, this.config.getPid(), this.config.getFactoryPid() );
Felix Meschberger273985f2012-07-05 12:28:06 +00001913 log( LogService.LOG_DEBUG, "Configuration {0} revoked from {1} (no more visibility)",
1914 new Object[]
1915 { config.getPid(), ConfigurationManager.toString( sr ) } );
1916 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001917 }
1918 else if ( !wasVisible && isVisible )
1919 {
1920 // call updated method
Felix Meschbergerfffde292012-11-18 18:02:20 +00001921 this.getHelper().provideConfiguration( sr, this.config.getPid(), this.config.getFactoryPid(),
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001922 this.properties, this.revision, null );
Felix Meschberger4f269292011-10-21 13:52:31 +00001923 log( LogService.LOG_DEBUG, "Configuration {0} provided to {1} (new visibility)", new Object[]
1924 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger35658d52011-10-20 21:43:58 +00001925 }
Felix Meschberger4f269292011-10-21 13:52:31 +00001926 else
Felix Meschberger35658d52011-10-20 21:43:58 +00001927 {
1928 // same visibility as before
Felix Meschberger4f269292011-10-21 13:52:31 +00001929 log( LogService.LOG_DEBUG, "Unmodified visibility to configuration {0} for {1}", new Object[]
1930 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001931 }
1932 }
1933 }
1934 }
1935
1936
Carsten Ziegeler014cca62015-05-11 18:17:28 +00001937 @Override
Felix Meschberger007c50e2011-10-20 12:39:38 +00001938 public String toString()
1939 {
1940 return "Location Changed (pid=" + config.getPid() + "): " + oldLocation + " ==> "
1941 + config.getBundleLocation();
1942 }
1943 }
1944
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001945 private class FireConfigurationEvent implements Runnable
1946 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001947 private final int type;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001948
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001949 private final String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001950
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001951 private final String factoryPid;
1952
1953 private final ServiceReference[] listenerReferences;
1954
1955 private final ConfigurationListener[] listeners;
1956
1957 private final Bundle[] listenerProvider;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001958
Felix Meschberger0770cad2012-06-11 12:36:52 +00001959 private ConfigurationEvent event;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001960
Felix Meschbergere94b1572012-07-14 11:59:29 +00001961 private FireConfigurationEvent( final ServiceTracker listenerTracker, final int type, final String pid, final String factoryPid)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001962 {
1963 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001964 this.pid = pid;
1965 this.factoryPid = factoryPid;
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001966
Felix Meschbergere94b1572012-07-14 11:59:29 +00001967 final ServiceReference[] srs = listenerTracker.getServiceReferences();
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001968 if ( srs == null || srs.length == 0 )
1969 {
1970 this.listenerReferences = null;
1971 this.listeners = null;
1972 this.listenerProvider = null;
1973 }
1974 else
1975 {
1976 this.listenerReferences = srs;
1977 this.listeners = new ConfigurationListener[srs.length];
1978 this.listenerProvider = new Bundle[srs.length];
1979 for ( int i = 0; i < srs.length; i++ )
1980 {
Felix Meschbergere94b1572012-07-14 11:59:29 +00001981 this.listeners[i] = ( ConfigurationListener ) listenerTracker.getService( srs[i] );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001982 this.listenerProvider[i] = srs[i].getBundle();
1983 }
1984 }
1985 }
1986
1987
1988 boolean hasConfigurationEventListeners()
1989 {
1990 return this.listenerReferences != null;
1991 }
1992
1993
1994 String getTypeName()
1995 {
1996 switch ( type )
1997 {
1998 case ConfigurationEvent.CM_DELETED:
1999 return "CM_DELETED";
2000 case ConfigurationEvent.CM_UPDATED:
2001 return "CM_UPDATED";
Felix Meschberger007c50e2011-10-20 12:39:38 +00002002 case ConfigurationEvent.CM_LOCATION_CHANGED:
2003 return "CM_LOCATION_CHANGED";
Felix Meschberger9967fbb2010-08-25 18:13:25 +00002004 default:
2005 return "<UNKNOWN(" + type + ")>";
2006 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002007 }
2008
2009
2010 public void run()
2011 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00002012 for ( int i = 0; i < listeners.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002013 {
Felix Meschberger0770cad2012-06-11 12:36:52 +00002014 sendEvent( i );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002015 }
2016 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00002017
Felix Meschberger0770cad2012-06-11 12:36:52 +00002018
Carsten Ziegeler014cca62015-05-11 18:17:28 +00002019 @Override
Felix Meschberger432e3872008-03-07 14:58:57 +00002020 public String toString()
2021 {
2022 return "Fire ConfigurationEvent: pid=" + pid;
2023 }
Felix Meschberger0770cad2012-06-11 12:36:52 +00002024
2025
2026 private ConfigurationEvent getConfigurationEvent()
2027 {
2028 if ( event == null )
2029 {
2030 this.event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
2031 }
2032 return event;
2033 }
2034
2035
2036 private void sendEvent( final int serviceIndex )
2037 {
A. J. David Bosschaert45ab8ed2015-04-17 11:55:37 +00002038 if ( (listenerProvider[serviceIndex].getState() & (Bundle.ACTIVE | Bundle.STARTING)) > 0
2039 && this.listeners[serviceIndex] != null )
Felix Meschberger0770cad2012-06-11 12:36:52 +00002040 {
2041 log( LogService.LOG_DEBUG, "Sending {0} event for {1} to {2}", new Object[]
2042 { getTypeName(), pid, ConfigurationManager.toString( listenerReferences[serviceIndex] ) } );
2043
2044 try
2045 {
2046 listeners[serviceIndex].configurationEvent( getConfigurationEvent() );
2047 }
2048 catch ( Throwable t )
2049 {
2050 log( LogService.LOG_ERROR, "Unexpected problem delivering configuration event to {0}", new Object[]
2051 { ConfigurationManager.toString( listenerReferences[serviceIndex] ), t } );
2052 }
2053 finally
2054 {
2055 this.listeners[serviceIndex] = null;
2056 }
2057 }
2058 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002059 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002060}
Felix Meschberger273985f2012-07-05 12:28:06 +00002061