blob: 021a57a15b054047d659b2e4cea6d5b9626e33de [file] [log] [blame]
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001/*
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.apache.felix.cm.impl;
20
21
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000022import java.io.IOException;
23import java.security.SecureRandom;
Felix Meschberger4f269292011-10-21 13:52:31 +000024import java.text.MessageFormat;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000025import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.Dictionary;
28import java.util.Enumeration;
29import java.util.HashMap;
30import java.util.Hashtable;
31import java.util.Iterator;
Felix Meschbergerc0894f32012-07-04 08:09:55 +000032import java.util.LinkedList;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000033import java.util.List;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000034import java.util.Random;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000035
36import org.apache.felix.cm.PersistenceManager;
37import org.apache.felix.cm.file.FilePersistenceManager;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000038import org.apache.felix.cm.impl.helper.BaseTracker;
Felix Meschberger3cbf4652012-10-18 06:49:39 +000039import org.apache.felix.cm.impl.helper.ConfigurationMap;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000040import org.apache.felix.cm.impl.helper.ManagedServiceFactoryTracker;
41import org.apache.felix.cm.impl.helper.ManagedServiceTracker;
42import org.apache.felix.cm.impl.helper.TargetedPID;
43import org.osgi.framework.Bundle;
44import org.osgi.framework.BundleActivator;
45import org.osgi.framework.BundleContext;
46import org.osgi.framework.BundleEvent;
47import org.osgi.framework.BundleListener;
48import org.osgi.framework.Constants;
49import org.osgi.framework.Filter;
50import org.osgi.framework.InvalidSyntaxException;
51import org.osgi.framework.ServiceReference;
52import org.osgi.framework.ServiceRegistration;
53import org.osgi.service.cm.ConfigurationAdmin;
54import org.osgi.service.cm.ConfigurationEvent;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000055import org.osgi.service.cm.ConfigurationListener;
56import org.osgi.service.cm.ConfigurationPermission;
57import org.osgi.service.cm.ConfigurationPlugin;
Felix Meschberger63e7ab12012-07-02 14:10:43 +000058import org.osgi.service.cm.SynchronousConfigurationListener;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000059import org.osgi.service.log.LogService;
60import org.osgi.util.tracker.ServiceTracker;
61
62
63/**
64 * The <code>ConfigurationManager</code> is the central class in this
65 * implementation of the Configuration Admin Service Specification. As such it
66 * has the following tasks:
67 * <ul>
68 * <li>It is a <code>BundleActivator</code> which is called when the bundle
69 * is started and stopped.
70 * <li>It is a <code>BundleListener</code> which gets informed when the
71 * states of bundles change. Mostly this is needed to unbind any bound
72 * configuration in case a bundle is uninstalled.
73 * <li>It is a <code>ServiceListener</code> which gets informed when
74 * <code>ManagedService</code> and <code>ManagedServiceFactory</code>
75 * services are registered and unregistered. This is used to provide
76 * configuration to these services. As a service listener it also listens for
77 * {@link PersistenceManager} instances being registered to support different
78 * configuration persistence layers.
79 * <li>A {@link ConfigurationAdminFactory} instance is registered as the
80 * <code>ConfigurationAdmin</code> service.
81 * <li>A {@link FilePersistenceManager} instance is registered as a default
82 * {@link PersistenceManager}.
83 * <li>Last but not least this instance manages all tasks laid out in the
84 * specification such as maintaining configuration, taking care of configuration
85 * events, etc.
86 * </ul>
87 * <p>
88 * The default {@link FilePersistenceManager} is configured with a configuration
89 * location taken from the <code>felix.cm.dir</code> framework property. If
90 * this property is not set the <code>config</code> directory in the current
91 * working directory as specified in the <code>user.dir</code> system property
92 * is used.
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000093 */
94public class ConfigurationManager implements BundleActivator, BundleListener
95{
96
97 /**
98 * The name of the bundle context property defining the location for the
99 * configuration files (value is "felix.cm.dir").
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000100 *
Carsten Ziegeler7853b9a2008-01-11 16:30:24 +0000101 * @see #start(BundleContext)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000102 */
103 public static final String CM_CONFIG_DIR = "felix.cm.dir";
104
Felix Meschberger08282c32009-01-28 07:01:55 +0000105 /**
106 * The name of the bundle context property defining the maximum log level
107 * (value is "felix.cm.loglevel"). The log level setting is only used if
108 * there is no OSGi LogService available. Otherwise this setting is ignored.
109 * <p>
110 * This value of this property is expected to be an integer number
111 * corresponding to the log level values of the OSGi LogService. That is 1
112 * for errors, 2 for warnings, 3 for informational messages and 4 for debug
113 * messages. The default value is 2, such that only warnings and errors are
114 * logged in the absence of a LogService.
115 */
116 public static final String CM_LOG_LEVEL = "felix.cm.loglevel";
117
Felix Meschberger85b355d2007-08-31 07:17:38 +0000118 // The name of the LogService (not using the class, which might be missing)
119 private static final String LOG_SERVICE_NAME = "org.osgi.service.log.LogService";
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000120
Felix Meschberger08282c32009-01-28 07:01:55 +0000121 private static final int CM_LOG_LEVEL_DEFAULT = 2;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000122
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000123 // random number generator to create configuration PIDs for factory
124 // configurations
Felix Meschberger417f66c2011-02-04 11:25:23 +0000125 private static Random numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000126
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000127 // the BundleContext of the Configuration Admin Service bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000128 BundleContext bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000129
Felix Meschberger99630732012-12-14 10:24:10 +0000130 // the service registration of the default file persistence manager
131 private volatile ServiceRegistration filepmRegistration;
132
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000133 // the service registration of the configuration admin
Felix Meschberger4b26df92011-02-01 12:41:45 +0000134 private volatile ServiceRegistration configurationAdminRegistration;
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000135
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000136 // the ServiceTracker to emit log services (see log(int, String, Throwable))
137 private ServiceTracker logTracker;
138
139 // the ConfigurationEvent listeners
140 private ServiceTracker configurationListenerTracker;
141
Felix Meschbergere94b1572012-07-14 11:59:29 +0000142 // the synchronous ConfigurationEvent listeners
143 private ServiceTracker syncConfigurationListenerTracker;
144
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000145 // service tracker for managed services
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000146 private ManagedServiceTracker managedServiceTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000147
148 // service tracker for managed service factories
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000149 private ManagedServiceFactoryTracker managedServiceFactoryTracker;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000150
151 // PersistenceManager services
152 private ServiceTracker persistenceManagerTracker;
153
154 // the thread used to schedule tasks required to run asynchronously
155 private UpdateThread updateThread;
156
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000157 // the thread used to schedule events to be dispatched asynchronously
158 private UpdateThread eventThread;
159
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000160 /**
161 * The actual list of {@link PersistenceManager persistence managers} to use
162 * when looking for configuration data. This list is built from the
163 * {@link #persistenceManagerMap}, which is ordered according to the
164 * {@link RankingComparator}.
165 */
166 private PersistenceManager[] persistenceManagers;
167
168 // the persistenceManagerTracker.getTrackingCount when the
169 // persistenceManagers were last got
170 private int pmtCount;
171
172 // the cache of Factory instances mapped by their factory PID
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000173 private final HashMap<String, Factory> factories = new HashMap<String, Factory>();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000174
175 // the cache of Configuration instances mapped by their PID
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000176 // have this always set to prevent NPE on bundle shutdown
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000177 private final HashMap<String, ConfigurationImpl> configurations = new HashMap<String, ConfigurationImpl>();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000178
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000179 /**
180 * The map of dynamic configuration bindings. This maps the
181 * PID of the dynamically bound configuration or factory to its bundle
182 * location.
183 * <p>
184 * On bundle startup this map is loaded from persistence and validated
185 * against the locations of installed bundles: Entries pointing to bundle
186 * locations not currently installed are removed.
187 * <p>
188 * The map is written to persistence on each change.
189 */
190 private DynamicBindings dynamicBindings;
191
Felix Meschberger08282c32009-01-28 07:01:55 +0000192 // the maximum log level when no LogService is available
193 private int logLevel = CM_LOG_LEVEL_DEFAULT;
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000194
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000195 // flag indicating whether BundleChange events should be consumed (FELIX-979)
196 private volatile boolean handleBundleEvents;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000197
Felix Meschberger623f7142012-01-31 07:13:37 +0000198 // flag indicating whether the manager is considered alive
199 private volatile boolean isActive;
200
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000201 public void start( BundleContext bundleContext )
202 {
203 // track the log service using a ServiceTracker
Felix Meschberger85b355d2007-08-31 07:17:38 +0000204 logTracker = new ServiceTracker( bundleContext, LOG_SERVICE_NAME , null );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000205 logTracker.open();
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000206
Felix Meschberger08282c32009-01-28 07:01:55 +0000207 // assign the log level
208 String logLevelProp = bundleContext.getProperty( CM_LOG_LEVEL );
209 if ( logLevelProp == null )
210 {
211 logLevel = CM_LOG_LEVEL_DEFAULT;
212 }
213 else
214 {
215 try
216 {
217 logLevel = Integer.parseInt( logLevelProp );
218 }
219 catch ( NumberFormatException nfe )
220 {
221 logLevel = CM_LOG_LEVEL_DEFAULT;
222 }
223 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000224
225 // set up some fields
226 this.bundleContext = bundleContext;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000227
228 // configurationlistener support
229 configurationListenerTracker = new ServiceTracker( bundleContext, ConfigurationListener.class.getName(), null );
230 configurationListenerTracker.open();
Felix Meschbergere94b1572012-07-14 11:59:29 +0000231 syncConfigurationListenerTracker = new ServiceTracker( bundleContext,
232 SynchronousConfigurationListener.class.getName(), null );
233 syncConfigurationListenerTracker.open();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000234
235 // initialize the asynchonous updater thread
Felix Meschbergerb68d1cf2010-08-26 08:46:36 +0000236 ThreadGroup tg = new ThreadGroup( "Configuration Admin Service" );
237 tg.setDaemon( true );
238 this.updateThread = new UpdateThread( this, tg, "CM Configuration Updater" );
239 this.eventThread = new UpdateThread( this, tg, "CM Event Dispatcher" );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000240
241 // set up the location (might throw IllegalArgumentException)
242 try
243 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000244 FilePersistenceManager fpm = new FilePersistenceManager( bundleContext, bundleContext
245 .getProperty( CM_CONFIG_DIR ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000246 Hashtable props = new Hashtable();
247 props.put( Constants.SERVICE_PID, fpm.getClass().getName() );
248 props.put( Constants.SERVICE_DESCRIPTION, "Platform Filesystem Persistence Manager" );
249 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
250 props.put( Constants.SERVICE_RANKING, new Integer( Integer.MIN_VALUE ) );
Felix Meschberger99630732012-12-14 10:24:10 +0000251 filepmRegistration = bundleContext.registerService( PersistenceManager.class.getName(), fpm, props );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000252
253 // setup dynamic configuration bindings
254 dynamicBindings = new DynamicBindings( bundleContext, fpm );
255 }
256 catch ( IOException ioe )
257 {
258 log( LogService.LOG_ERROR, "Failure setting up dynamic configuration bindings", ioe );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000259 }
260 catch ( IllegalArgumentException iae )
261 {
262 log( LogService.LOG_ERROR, "Cannot create the FilePersistenceManager", iae );
263 }
264
265 // register as bundle and service listener
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000266 handleBundleEvents = true;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000267 bundleContext.addBundleListener( this );
268
269 // get all persistence managers to begin with
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000270 pmtCount = 1; // make sure to get the persistence managers at least once
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000271 persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
272 persistenceManagerTracker.open();
273
Felix Meschberger623f7142012-01-31 07:13:37 +0000274 // consider alive now (before clients use Configuration Admin
275 // service registered in the next step)
276 isActive = true;
277
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000278 // create and register configuration admin - start after PM tracker ...
279 ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
280 Hashtable props = new Hashtable();
281 props.put( Constants.SERVICE_PID, "org.apache.felix.cm.ConfigurationAdmin" );
282 props.put( Constants.SERVICE_DESCRIPTION, "Configuration Admin Service Specification 1.2 Implementation" );
283 props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000284 configurationAdminRegistration = bundleContext.registerService( ConfigurationAdmin.class.getName(), caf, props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000285
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000286 // start handling ManagedService[Factory] services
287 managedServiceTracker = new ManagedServiceTracker(this);
288 managedServiceFactoryTracker = new ManagedServiceFactoryTracker(this);
289
Felix Meschberger4b26df92011-02-01 12:41:45 +0000290 // start processing the event queues only after registering the service
291 // see FELIX-2813 for details
292 this.updateThread.start();
293 this.eventThread.start();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000294 }
295
296
297 public void stop( BundleContext bundleContext )
298 {
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000299
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000300 // stop handling bundle events immediately
301 handleBundleEvents = false;
302
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000303 // stop handling ManagedService[Factory] services
304 managedServiceFactoryTracker.close();
305 managedServiceTracker.close();
306
Felix Meschberger4b26df92011-02-01 12:41:45 +0000307 // stop queue processing before unregistering the service
308 // see FELIX-2813 for details
309 if ( updateThread != null )
310 {
311 updateThread.terminate();
312 }
313 if ( eventThread != null )
314 {
315 eventThread.terminate();
316 }
317
Felix Meschbergerdb90b1b2007-09-06 08:18:10 +0000318 // immediately unregister the Configuration Admin before cleaning up
Felix Meschberger10568352009-01-15 08:57:11 +0000319 // clearing the field before actually unregistering the service
320 // prevents IllegalStateException in getServiceReference() if
321 // the field is not null but the service already unregistered
Felix Meschberger99630732012-12-14 10:24:10 +0000322 final ServiceRegistration caReg = configurationAdminRegistration;
323 configurationAdminRegistration = null;
324 if ( caReg != null )
325 {
326 caReg.unregister();
Felix Meschberger10568352009-01-15 08:57:11 +0000327 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000328
Felix Meschberger623f7142012-01-31 07:13:37 +0000329 // consider inactive after unregistering such that during
330 // unregistration the manager is still alive and can react
331 isActive = false;
332
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000333 // don't care for PersistenceManagers any more
334 persistenceManagerTracker.close();
335
Felix Meschberger99630732012-12-14 10:24:10 +0000336 // shutdown the file persistence manager
337 final ServiceRegistration filePmReg = filepmRegistration;
338 filepmRegistration = null;
339 if ( filePmReg != null )
340 {
341 filePmReg.unregister();
342 }
343
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000344 // stop listening for events
345 bundleContext.removeBundleListener( this );
346
347 if ( configurationListenerTracker != null )
348 {
349 configurationListenerTracker.close();
350 }
351
Felix Meschbergere94b1572012-07-14 11:59:29 +0000352 if ( syncConfigurationListenerTracker != null )
353 {
354 syncConfigurationListenerTracker.close();
355 }
356
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000357 if ( logTracker != null )
358 {
359 logTracker.close();
360 }
361
Felix Meschberger6a698df2009-08-16 18:38:46 +0000362 // just ensure the configuration cache is empty
Felix Meschberger5d3e7ac2009-08-14 21:45:10 +0000363 synchronized ( configurations )
364 {
365 configurations.clear();
366 }
367
Felix Meschberger6a698df2009-08-16 18:38:46 +0000368 // just ensure the factory cache is empty
369 synchronized ( factories )
370 {
371 factories.clear();
372 }
373
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000374 this.bundleContext = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000375 }
376
377
Felix Meschberger623f7142012-01-31 07:13:37 +0000378 /**
379 * Returns <code>true</code> if this manager is considered active.
380 */
381 boolean isActive()
382 {
383 return isActive;
384 }
385
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000386 public BundleContext getBundleContext()
387 {
388 return bundleContext;
389 }
Felix Meschberger623f7142012-01-31 07:13:37 +0000390
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000391 // ---------- Configuration caching support --------------------------------
392
393 ConfigurationImpl getCachedConfiguration( String pid )
394 {
395 synchronized ( configurations )
396 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000397 return configurations.get( pid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000398 }
399 }
400
401
Felix Meschberger6a698df2009-08-16 18:38:46 +0000402 ConfigurationImpl[] getCachedConfigurations()
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000403 {
404 synchronized ( configurations )
405 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000406 return configurations.values().toArray(
Felix Meschberger6a698df2009-08-16 18:38:46 +0000407 new ConfigurationImpl[configurations.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000408 }
409 }
410
411
Felix Meschberger2941ef92007-08-20 13:15:16 +0000412 ConfigurationImpl cacheConfiguration( ConfigurationImpl configuration )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000413 {
414 synchronized ( configurations )
415 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000416 final String pid = configuration.getPidString();
417 final Object existing = configurations.get( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000418 if ( existing != null )
419 {
420 return ( ConfigurationImpl ) existing;
421 }
422
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000423 configurations.put( pid, configuration );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000424 return configuration;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000425 }
426 }
427
428
429 void removeConfiguration( ConfigurationImpl configuration )
430 {
431 synchronized ( configurations )
432 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000433 configurations.remove( configuration.getPidString() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000434 }
435 }
436
437
Felix Meschberger6a698df2009-08-16 18:38:46 +0000438 Factory getCachedFactory( String factoryPid )
439 {
440 synchronized ( factories )
441 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000442 return factories.get( factoryPid );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000443 }
444 }
445
446
447 Factory[] getCachedFactories()
448 {
449 synchronized ( factories )
450 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000451 return factories.values().toArray( new Factory[factories.size()] );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000452 }
453 }
454
455
456 void cacheFactory( Factory factory )
457 {
458 synchronized ( factories )
459 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000460 factories.put( factory.getFactoryPidString(), factory );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000461 }
462 }
463
464
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000465 // ---------- ConfigurationAdminImpl support
Felix Meschberger6a698df2009-08-16 18:38:46 +0000466
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000467 void setDynamicBundleLocation( final String pid, final String location )
468 {
469 if ( dynamicBindings != null )
470 {
471 try
472 {
473 dynamicBindings.putLocation( pid, location );
474 }
475 catch ( IOException ioe )
476 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000477 log( LogService.LOG_ERROR, "Failed storing dynamic configuration binding for {0} to {1}", new Object[]
478 { pid, location, ioe } );
Felix Meschberger3f9e4da2009-08-17 07:52:39 +0000479 }
480 }
481 }
482
483
484 String getDynamicBundleLocation( final String pid )
485 {
486 if ( dynamicBindings != null )
487 {
488 return dynamicBindings.getLocation( pid );
489 }
490
491 return null;
492 }
493
494
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000495 ConfigurationImpl createFactoryConfiguration( String factoryPid, String location ) throws IOException
496 {
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000497 return cacheConfiguration( createConfiguration( createPid( factoryPid ), factoryPid, location ) );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000498 }
499
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000500 /**
501 * Returns a targeted configuration for the given service PID and
502 * the reference target service.
Felix Meschberger273985f2012-07-05 12:28:06 +0000503 * <p>
504 * A configuration returned has already been checked for visibility
505 * by the bundle registering the referenced service. Additionally,
506 * the configuration is also dynamically bound if needed.
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000507 *
508 * @param rawPid The raw service PID to get targeted configuration for.
509 * @param target The target <code>ServiceReference</code> to get
510 * configuration for.
511 * @return The best matching targeted configuration or <code>null</code>
512 * if there is no configuration at all.
513 * @throwss IOException if an error occurrs reading configurations
514 * from persistence.
515 */
516 ConfigurationImpl getTargetedConfiguration( final String rawPid, final ServiceReference target ) throws IOException
517 {
518 final Bundle serviceBundle = target.getBundle();
519 if ( serviceBundle != null )
520 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000521 // list of targeted PIDs to check
522 // (StringBuffer for pre-1.5 API compatibility)
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000523 final StringBuffer targetedPid = new StringBuffer( rawPid );
524 int i = 3;
525 String[] names = new String[4];
526 names[i--] = targetedPid.toString();
527 targetedPid.append( '|' ).append( serviceBundle.getSymbolicName() );
528 names[i--] = targetedPid.toString();
529 targetedPid.append( '|' ).append( TargetedPID.getBundleVersion( serviceBundle ) );
530 names[i--] = targetedPid.toString();
531 targetedPid.append( '|' ).append( serviceBundle.getLocation() );
532 names[i--] = targetedPid.toString();
533
534 for ( String candidate : names )
535 {
536 ConfigurationImpl config = getConfiguration( candidate );
Felix Meschbergercd5195f2012-07-05 17:17:45 +0000537 if ( config != null && !config.isDeleted() )
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000538 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000539 // check visibility to use and dynamically bind
540 if ( canReceive( serviceBundle, config.getBundleLocation() ) )
541 {
542 config.tryBindLocation( serviceBundle.getLocation() );
543 return config;
544 }
545
546 // CM 1.4 / 104.13.2.2 / 104.5.3
547 // act as if there is no configuration
548 log(
549 LogService.LOG_DEBUG,
550 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}; calling with null",
551 new Object[]
552 { config.getPid(), toString( target ), config.getBundleLocation() } );
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000553 }
554 }
555 }
Felix Meschberger273985f2012-07-05 12:28:06 +0000556 else
557 {
558 log( LogService.LOG_INFO,
559 "Service for PID {0} seems to already have been unregistered, not updating with configuration",
560 new Object[]
561 { rawPid } );
562 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000563
564 // service already unregistered, nothing to do really
565 return null;
566 }
567
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000568
Felix Meschbergerad949872011-11-16 10:34:54 +0000569 /**
570 * Returns the {@link ConfigurationImpl} with the given PID if
571 * available in the internal cache or from any persistence manager.
572 * Otherwise <code>null</code> is returned.
573 *
574 * @param pid The PID for which to return the configuration
575 * @return The configuration or <code>null</code> if non exists
576 * @throws IOException If an error occurrs reading from a persistence
577 * manager.
578 */
579 ConfigurationImpl getConfiguration( String pid ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000580 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000581 ConfigurationImpl config = getCachedConfiguration( pid );
582 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000583 {
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000584 log( LogService.LOG_DEBUG, "Found cached configuration {0} bound to {1}", new Object[]
585 { pid, config.getBundleLocation() } );
Felix Meschbergerb3bae582012-02-16 14:00:52 +0000586
587 config.ensureFactoryConfigPersisted();
588
Felix Meschberger2941ef92007-08-20 13:15:16 +0000589 return config;
590 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000591
Felix Meschberger2941ef92007-08-20 13:15:16 +0000592 PersistenceManager[] pmList = getPersistenceManagers();
593 for ( int i = 0; i < pmList.length; i++ )
594 {
595 if ( pmList[i].exists( pid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000596 {
Felix Meschberger2941ef92007-08-20 13:15:16 +0000597 Dictionary props = pmList[i].load( pid );
598 config = new ConfigurationImpl( this, pmList[i], props );
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000599 log( LogService.LOG_DEBUG, "Found existing configuration {0} bound to {1}", new Object[]
600 { pid, config.getBundleLocation() } );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000601 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000602 }
603 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000604
Felix Meschberger2941ef92007-08-20 13:15:16 +0000605 // neither the cache nor any persistence manager has configuration
606 return null;
607 }
Felix Meschberger2fd5b582007-12-10 10:32:29 +0000608
609
Felix Meschbergerad949872011-11-16 10:34:54 +0000610 /**
611 * Creates a regular (non-factory) configuration for the given PID
612 * setting the bundle location accordingly.
613 * <p>
614 * This method assumes the configuration to not exist yet and will
615 * create it without further checking.
616 *
617 * @param pid The PID of the new configuration
618 * @param bundleLocation The location to set on the new configuration.
619 * This may be <code>null</code> to not bind the configuration
620 * yet.
621 * @return The new configuration persisted in the first persistence
622 * manager.
623 * @throws IOException If an error occurrs writing the configuration
624 * to the persistence.
625 */
626 ConfigurationImpl createConfiguration( String pid, String bundleLocation ) throws IOException
Felix Meschberger2941ef92007-08-20 13:15:16 +0000627 {
628 // check for existing (cached or persistent) configuration
Felix Meschbergerad949872011-11-16 10:34:54 +0000629 ConfigurationImpl config = getConfiguration( pid );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000630 if ( config != null )
631 {
632 return config;
633 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000634
Felix Meschberger2941ef92007-08-20 13:15:16 +0000635 // else create new configuration also setting the bundle location
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000636 // and cache the new configuration
637 config = createConfiguration( pid, null, bundleLocation );
638 return cacheConfiguration( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000639 }
640
641
642 ConfigurationImpl[] listConfigurations( ConfigurationAdminImpl configurationAdmin, String filterString )
643 throws IOException, InvalidSyntaxException
644 {
645 Filter filter = null;
646 if ( filterString != null )
647 {
648 filter = bundleContext.createFilter( filterString );
649 }
650
Felix Meschberger4f269292011-10-21 13:52:31 +0000651 log( LogService.LOG_DEBUG, "Listing configurations matching {0}", new Object[]
652 { filterString } );
653
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000654 List configList = new ArrayList();
655
656 PersistenceManager[] pmList = getPersistenceManagers();
657 for ( int i = 0; i < pmList.length; i++ )
658 {
659 Enumeration configs = pmList[i].getDictionaries();
660 while ( configs.hasMoreElements() )
661 {
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000662 final Dictionary config = ( Dictionary ) configs.nextElement();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000663
664 // ignore non-Configuration dictionaries
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000665 final String pid = ( String ) config.get( Constants.SERVICE_PID );
Felix Meschberger86a0d172007-07-04 07:15:01 +0000666 if ( pid == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000667 {
668 continue;
669 }
670
Felix Meschberger007c50e2011-10-20 12:39:38 +0000671 // CM 1.4 / 104.13.2.3 Permission required
Felix Meschberger274aa242012-12-31 19:46:31 +0000672 if ( !configurationAdmin.hasPermission( this,
673 ( String ) config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000674 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000675 log(
676 LogService.LOG_DEBUG,
Felix Meschbergerfb833e72011-10-27 06:12:37 +0000677 "Omitting configuration {0}: No permission for bundle {1} on configuration bound to {2}",
Felix Meschberger4f269292011-10-21 13:52:31 +0000678 new Object[]
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000679 { pid, configurationAdmin.getBundle().getLocation(),
Felix Meschberger4f269292011-10-21 13:52:31 +0000680 config.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000681 continue;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000682 }
683
684 // check filter
685 if ( filter == null || filter.match( config ) )
686 {
Felix Meschberger86a0d172007-07-04 07:15:01 +0000687 // ensure the service.pid and returned a cached config if available
688 ConfigurationImpl cfg = getCachedConfiguration( pid );
689 if ( cfg == null )
690 {
691 cfg = new ConfigurationImpl( this, pmList[i], config );
692 }
693
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000694 // FELIX-611: Ignore configuration objects without props
695 if ( !cfg.isNew() )
696 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000697 log( LogService.LOG_DEBUG, "Adding configuration {0}", new Object[]
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000698 { pid } );
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000699 configList.add( cfg );
700 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000701 else
702 {
703 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Is new", new Object[]
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000704 { pid } );
Felix Meschberger4f269292011-10-21 13:52:31 +0000705 }
706 } else {
707 log( LogService.LOG_DEBUG, "Omitting configuration {0}: Does not match filter", new Object[]
Felix Meschbergera8922bd2012-08-06 12:15:03 +0000708 { pid } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000709 }
710 }
711 }
712
Felix Meschberger8faceff2007-07-04 07:19:48 +0000713 return ( ConfigurationImpl[] ) configList.toArray( new ConfigurationImpl[configList
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000714 .size()] );
715 }
716
717
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000718 void deleted( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000719 {
720 // remove the configuration from the cache
721 removeConfiguration( config );
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000722 fireConfigurationEvent( ConfigurationEvent.CM_DELETED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000723 updateThread.schedule( new DeleteConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000724 log( LogService.LOG_DEBUG, "DeleteConfiguration({0}) scheduled", new Object[]
725 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000726 }
727
728
Felix Meschbergerce67d732009-08-20 06:26:35 +0000729 void updated( ConfigurationImpl config, boolean fireEvent )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000730 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000731 if ( fireEvent )
732 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000733 fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000734 }
735 updateThread.schedule( new UpdateConfiguration( config ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000736 log( LogService.LOG_DEBUG, "UpdateConfiguration({0}) scheduled", new Object[]
737 { config.getPid() } );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000738 }
739
740
Felix Meschberger007c50e2011-10-20 12:39:38 +0000741 void locationChanged( ConfigurationImpl config, String oldLocation )
742 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000743 fireConfigurationEvent( ConfigurationEvent.CM_LOCATION_CHANGED, config.getPidString(), config.getFactoryPidString() );
Felix Meschberger35658d52011-10-20 21:43:58 +0000744 if ( oldLocation != null && !config.isNew() )
Felix Meschberger007c50e2011-10-20 12:39:38 +0000745 {
746 updateThread.schedule( new LocationChanged( config, oldLocation ) );
Felix Meschberger4f269292011-10-21 13:52:31 +0000747 log( LogService.LOG_DEBUG, "LocationChanged({0}, {1}=>{2}) scheduled", new Object[]
748 { config.getPid(), oldLocation, config.getBundleLocation() } );
Felix Meschberger35658d52011-10-20 21:43:58 +0000749 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000750 else
Felix Meschberger35658d52011-10-20 21:43:58 +0000751 {
752 log( LogService.LOG_DEBUG,
Felix Meschberger4f269292011-10-21 13:52:31 +0000753 "LocationChanged not scheduled for {0} (old location is null or configuration is new)", new Object[]
754 { config.getPid() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +0000755 }
756 }
757
758
Felix Meschberger66423332007-08-22 08:46:34 +0000759 void fireConfigurationEvent( int type, String pid, String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000760 {
Felix Meschbergere94b1572012-07-14 11:59:29 +0000761 // prevent event senders
762 FireConfigurationEvent asyncSender = new FireConfigurationEvent( this.configurationListenerTracker, type, pid,
763 factoryPid );
764 FireConfigurationEvent syncSender = new FireConfigurationEvent( this.syncConfigurationListenerTracker, type,
765 pid, factoryPid );
766
767 // send synchronous events
768 if ( syncSender.hasConfigurationEventListeners() )
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000769 {
Felix Meschbergere94b1572012-07-14 11:59:29 +0000770 syncSender.run();
771 }
772 else
773 {
774 log( LogService.LOG_DEBUG, "No SynchronousConfigurationListeners to send {0} event to.", new Object[]
775 { syncSender.getTypeName() } );
776 }
777
778 // schedule asynchronous events
779 if ( asyncSender.hasConfigurationEventListeners() )
780 {
781 eventThread.schedule( asyncSender );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000782 }
Felix Meschberger4f269292011-10-21 13:52:31 +0000783 else
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000784 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000785 log( LogService.LOG_DEBUG, "No ConfigurationListeners to send {0} event to.", new Object[]
Felix Meschbergere94b1572012-07-14 11:59:29 +0000786 { asyncSender.getTypeName() } );
Felix Meschberger9967fbb2010-08-25 18:13:25 +0000787 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000788 }
789
790
791 // ---------- BundleListener -----------------------------------------------
792
793 public void bundleChanged( BundleEvent event )
794 {
Felix Meschberger2c2a5be2009-03-26 16:47:01 +0000795 if ( event.getType() == BundleEvent.UNINSTALLED && handleBundleEvents )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000796 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000797 final String location = event.getBundle().getLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000798
Felix Meschberger6a698df2009-08-16 18:38:46 +0000799 // we only reset dynamic bindings, which are only present in
800 // cached configurations, hence only consider cached configs here
801 final ConfigurationImpl[] configs = getCachedConfigurations();
802 for ( int i = 0; i < configs.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000803 {
Felix Meschberger6a698df2009-08-16 18:38:46 +0000804 final ConfigurationImpl cfg = configs[i];
Felix Meschberger41cce522009-08-19 05:54:40 +0000805 if ( location.equals( cfg.getDynamicBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000806 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000807 cfg.setDynamicBundleLocation( null, true );
Felix Meschberger6a698df2009-08-16 18:38:46 +0000808 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000809 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000810 }
811 }
812
813
814 // ---------- internal -----------------------------------------------------
815
816 private PersistenceManager[] getPersistenceManagers()
817 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000818 int currentPmtCount = persistenceManagerTracker.getTrackingCount();
819 if ( persistenceManagers == null || currentPmtCount > pmtCount )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000820 {
821
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000822 List pmList = new ArrayList();
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000823 PersistenceManager[] pm;
824
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000825 ServiceReference[] refs = persistenceManagerTracker.getServiceReferences();
826 if ( refs == null || refs.length == 0 )
827 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000828 pm = new PersistenceManager[0];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000829 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000830 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000831 {
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000832 // sort the references according to the cmRanking property
Felix Meschberger007c50e2011-10-20 12:39:38 +0000833 if ( refs.length > 1 )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000834 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000835 Arrays.sort( refs, RankingComparator.SRV_RANKING );
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000836 }
837
838 // create the service array from the sorted set of referenecs
Felix Meschberger007c50e2011-10-20 12:39:38 +0000839 for ( int i = 0; i < refs.length; i++ )
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000840 {
Felix Meschberger007c50e2011-10-20 12:39:38 +0000841 Object service = persistenceManagerTracker.getService( refs[i] );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000842 if ( service != null )
843 {
Felix Meschbergera86cdfc2010-08-25 09:32:36 +0000844 pmList.add( new CachingPersistenceManagerProxy( ( PersistenceManager ) service ) );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000845 }
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000846 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000847
848 pm = ( PersistenceManager[] ) pmList.toArray( new PersistenceManager[pmList.size()] );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000849 }
850
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000851 pmtCount = pm.length;
Felix Meschbergerd71f4102007-07-06 15:34:32 +0000852 persistenceManagers = pm;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000853 }
854
855 return persistenceManagers;
856 }
857
858
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000859 private ServiceReference getServiceReference()
860 {
861 ServiceRegistration reg = configurationAdminRegistration;
Felix Meschberger0770cad2012-06-11 12:36:52 +0000862 if (reg != null) {
863 return reg.getReference();
864 }
865
866 // probably called for firing an event during service registration
867 // since we didn't get the service registration yet we use the
868 // service registry to get our service reference
869 BundleContext context = bundleContext;
870 if ( context != null )
871 {
872 try
873 {
874 ServiceReference[] refs = context.getServiceReferences( ConfigurationAdmin.class.getName(), null );
875 if ( refs != null )
876 {
877 for ( int i = 0; i < refs.length; i++ )
878 {
879 if ( refs[i].getBundle().getBundleId() == context.getBundle().getBundleId() )
880 {
881 return refs[i];
882 }
883 }
884 }
885 }
886 catch ( InvalidSyntaxException e )
887 {
888 // unexpected since there is no filter
889 }
890 }
891
892 // service references
893 return null;
Felix Meschbergerb4f83e42009-01-15 08:53:36 +0000894 }
895
896
Felix Meschberger05d89e12011-11-03 23:37:10 +0000897 /**
898 * Configures the ManagedService and returns the service.pid
899 * service property as a String[], which may be <code>null</code> if
900 * the ManagedService does not have such a property.
901 */
Felix Meschberger05d89e12011-11-03 23:37:10 +0000902 /**
903 * Configures the ManagedServiceFactory and returns the service.pid
904 * service property as a String[], which may be <code>null</code> if
905 * the ManagedServiceFactory does not have such a property.
906 */
Felix Meschberger382a19b2012-07-03 09:45:14 +0000907 /**
908 * Schedules the configuration of the referenced service with
909 * configuration for the given PID.
910 *
Felix Meschberger273985f2012-07-05 12:28:06 +0000911 * @param pid The list of service PID of the configurations to be
912 * provided to the referenced service.
Felix Meschberger382a19b2012-07-03 09:45:14 +0000913 * @param sr The <code>ServiceReference</code> to the service
914 * to be configured.
915 * @param factory <code>true</code> If the service is considered to
916 * be a <code>ManagedServiceFactory</code>. Otherwise the service
917 * is considered to be a <code>ManagedService</code>.
918 */
Felix Meschberger3cbf4652012-10-18 06:49:39 +0000919 public void configure( String[] pid, ServiceReference sr, final boolean factory, final ConfigurationMap<?> configs )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000920 {
Felix Meschberger273985f2012-07-05 12:28:06 +0000921 if ( this.isLogEnabled( LogService.LOG_DEBUG ) )
922 {
923 this.log( LogService.LOG_DEBUG, "configure(ManagedService {0})", new Object[]
924 { toString( sr ) } );
925 }
926
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000927 Runnable r;
928 if ( factory )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000929 {
Felix Meschberger3cbf4652012-10-18 06:49:39 +0000930 r = new ManagedServiceFactoryUpdate( pid, sr, configs );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000931 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000932 else
933 {
Felix Meschberger3cbf4652012-10-18 06:49:39 +0000934 r = new ManagedServiceUpdate( pid, sr, configs );
Felix Meschberger63e7ab12012-07-02 14:10:43 +0000935 }
936 updateThread.schedule( r );
937 log( LogService.LOG_DEBUG, "[{0}] scheduled", new Object[]
938 { r } );
Felix Meschberger851c6412009-08-16 18:43:26 +0000939 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000940
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000941
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000942 /**
943 * Factory method to create a new configuration object. The configuration
944 * object returned is not stored in configuration cache and only persisted
945 * if the <code>factoryPid</code> parameter is <code>null</code>.
Felix Meschberger5dfaa962009-08-14 19:26:01 +0000946 *
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000947 * @param pid
948 * The PID of the new configuration object. Must not be
949 * <code>null</code>.
950 * @param factoryPid
951 * The factory PID of the new configuration. Not
Felix Meschberger6a698df2009-08-16 18:38:46 +0000952 * <code>null</code> if the new configuration object belongs to a
953 * factory. The configuration object will not be persisted if
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000954 * this parameter is not <code>null</code>.
955 * @param bundleLocation
956 * The bundle location of the bundle to which the configuration
Felix Meschberger6a698df2009-08-16 18:38:46 +0000957 * belongs or <code>null</code> if the configuration is not bound
958 * yet.
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000959 * @return The new configuration object
960 * @throws IOException
961 * May be thrown if an error occurrs persisting the new
962 * configuration object.
963 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000964 ConfigurationImpl createConfiguration( String pid, String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000965 {
Felix Meschberger4f269292011-10-21 13:52:31 +0000966 log( LogService.LOG_DEBUG, "createConfiguration({0}, {1}, {2})", new Object[]
967 { pid, factoryPid, bundleLocation } );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000968 return new ConfigurationImpl( this, getPersistenceManagers()[0], pid, factoryPid, bundleLocation );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000969 }
970
971
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000972 /**
973 * Returns a list of {@link Factory} instances according to the
974 * Configuration Admin 1.5 specification for targeted PIDs (Section
975 * 104.3.2)
976 *
977 * @param rawFactoryPid The raw factory PID without any targetting.
978 * @param target The <code>ServiceReference</code> of the service to
979 * be supplied with targeted configuration.
980 * @return A list of {@link Factory} instances as listed above. This
981 * list will always at least include an instance for the
982 * <code>rawFactoryPid</code>. Other instances are only included
983 * if existing.
984 * @throws IOException If an error occurrs reading any of the
985 * {@link Factory} instances from persistence
986 */
987 List<Factory> getTargetedFactories( final String rawFactoryPid, final ServiceReference target ) throws IOException
988 {
989 LinkedList<Factory> factories = new LinkedList<Factory>();
990
991 final Bundle serviceBundle = target.getBundle();
992 if ( serviceBundle != null )
993 {
994 // for pre-1.5 API compatibility
995 final StringBuffer targetedPid = new StringBuffer( rawFactoryPid );
996 factories.add( getOrCreateFactory( targetedPid.toString() ) );
997
998 targetedPid.append( '|' ).append( serviceBundle.getSymbolicName() );
999 Factory f = getFactory( targetedPid.toString() );
1000 if ( f != null )
1001 {
1002 factories.add( 0, f );
1003 }
1004
1005 targetedPid.append( '|' ).append( TargetedPID.getBundleVersion( serviceBundle ) );
1006 f = getFactory( targetedPid.toString() );
1007 if ( f != null )
1008 {
1009 factories.add( 0, f );
1010 }
1011
1012 targetedPid.append( '|' ).append( serviceBundle.getLocation() );
1013 f = getFactory( targetedPid.toString() );
1014 if ( f != null )
1015 {
1016 factories.add( 0, f );
1017 }
1018 }
1019
1020 return factories;
1021 }
1022
1023
1024 /**
1025 * Gets the factory with the exact identifier from the cached or from
1026 * the persistence managers. If no factory exists already one is
1027 * created and cached.
1028 *
1029 * @param factoryPid The PID of the {@link Factory} to return
1030 * @return The existing or newly created {@link Factory}
1031 * @throws IOException If an error occurrs reading the factory from
1032 * a {@link PersistenceManager}
1033 */
1034 Factory getOrCreateFactory( String factoryPid ) throws IOException
1035 {
1036 Factory factory = getFactory( factoryPid );
1037 if ( factory != null )
1038 {
1039 return factory;
1040 }
1041
1042 return createFactory( factoryPid );
1043 }
1044
1045
1046 /**
1047 * Gets the factory with the exact identifier from the cached or from
1048 * the persistence managers. If no factory exists <code>null</code>
1049 * is returned.
1050 *
1051 * @param factoryPid The PID of the {@link Factory} to return
1052 * @return The existing {@link Factory} or <code>null</code>
1053 * @throws IOException If an error occurrs reading the factory from
1054 * a {@link PersistenceManager}
1055 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001056 Factory getFactory( String factoryPid ) throws IOException
1057 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001058 // check for cached factory
Felix Meschbergerf4631322008-03-10 12:32:35 +00001059 Factory factory = getCachedFactory( factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001060 if ( factory != null )
1061 {
1062 return factory;
1063 }
1064
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001065 // try to load factory from persistence
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001066 PersistenceManager[] pmList = getPersistenceManagers();
1067 for ( int i = 0; i < pmList.length; i++ )
1068 {
1069 if ( Factory.exists( pmList[i], factoryPid ) )
1070 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +00001071 factory = Factory.load( this, pmList[i], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001072 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001073 return factory;
1074 }
1075 }
1076
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001077 // no existing factory
1078 return null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001079 }
1080
1081
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001082 /**
1083 * Creates a new factory with the given <code>factoryPid</code>.
1084 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001085 Factory createFactory( String factoryPid )
1086 {
Felix Meschberger3f9e4da2009-08-17 07:52:39 +00001087 Factory factory = new Factory( this, getPersistenceManagers()[0], factoryPid );
Felix Meschbergerf4631322008-03-10 12:32:35 +00001088 cacheFactory( factory );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001089 return factory;
1090 }
1091
1092
Felix Meschberger2941ef92007-08-20 13:15:16 +00001093 /**
1094 * Calls the registered configuration plugins on the given configuration
Felix Meschberger273985f2012-07-05 12:28:06 +00001095 * properties from the given configuration object.
1096 * <p>
1097 * The plugins to be called are selected as <code>ConfigurationPlugin</code>
1098 * services registered with a <code>cm.target</code> property set to
1099 * <code>*</code> or the factory PID of the configuration (for factory
1100 * configurations) or the PID of the configuration (for non-factory
1101 * configurations).
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001102 *
Felix Meschberger41cce522009-08-19 05:54:40 +00001103 * @param props The configuraiton properties run through the registered
Felix Meschberger273985f2012-07-05 12:28:06 +00001104 * ConfigurationPlugin services. This must not be
1105 * <code>null</code>.
Felix Meschberger2941ef92007-08-20 13:15:16 +00001106 * @param sr The service reference of the managed service (factory) which
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001107 * is to be updated with configuration
Felix Meschberger273985f2012-07-05 12:28:06 +00001108 * @param configPid The PID of the configuration object whose properties
1109 * are to be augmented
1110 * @param factoryPid the factory PID of the configuration object whose
1111 * properties are to be augmented. This is non-<code>null</code>
1112 * only for a factory configuration.
Felix Meschberger2941ef92007-08-20 13:15:16 +00001113 */
Felix Meschberger273985f2012-07-05 12:28:06 +00001114 public void callPlugins( final Dictionary props, final ServiceReference sr, final String configPid,
1115 final String factoryPid )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001116 {
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001117 ServiceReference[] plugins = null;
1118 try
1119 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001120 final String targetPid = (factoryPid == null) ? configPid : factoryPid;
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001121 String filter = "(|(!(cm.target=*))(cm.target=" + targetPid + "))";
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001122 plugins = bundleContext.getServiceReferences( ConfigurationPlugin.class.getName(), filter );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001123 }
1124 catch ( InvalidSyntaxException ise )
1125 {
1126 // no filter, no exception ...
1127 }
1128
1129 // abort early if there are no plugins
1130 if ( plugins == null || plugins.length == 0 )
1131 {
Felix Meschberger41cce522009-08-19 05:54:40 +00001132 return;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001133 }
1134
1135 // sort the plugins by their service.cmRanking
Felix Meschberger007c50e2011-10-20 12:39:38 +00001136 if ( plugins.length > 1 )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001137 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001138 Arrays.sort( plugins, RankingComparator.CM_RANKING );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001139 }
1140
1141 // call the plugins in order
Felix Meschberger007c50e2011-10-20 12:39:38 +00001142 for ( int i = 0; i < plugins.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001143 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001144 ServiceReference pluginRef = plugins[i];
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001145 ConfigurationPlugin plugin = ( ConfigurationPlugin ) bundleContext.getService( pluginRef );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001146 if ( plugin != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001147 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001148 try
1149 {
1150 plugin.modifyConfiguration( sr, props );
1151 }
1152 catch ( Throwable t )
1153 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001154 log( LogService.LOG_ERROR, "Unexpected problem calling configuration plugin {0}", new Object[]
1155 { toString( pluginRef ), t } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001156 }
1157 finally
1158 {
1159 // ensure ungetting the plugin
1160 bundleContext.ungetService( pluginRef );
1161 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001162 ConfigurationImpl.setAutoProperties( props, configPid, factoryPid );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001163 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001164 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001165 }
1166
1167
1168 /**
1169 * Creates a PID for the given factoryPid
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001170 *
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001171 * @param factoryPid
1172 * @return
1173 */
1174 private static String createPid( String factoryPid )
1175 {
Felix Meschberger417f66c2011-02-04 11:25:23 +00001176 Random ng = numberGenerator;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001177 if ( ng == null )
1178 {
Felix Meschberger417f66c2011-02-04 11:25:23 +00001179 // FELIX-2771 Secure Random not available on Mika
1180 try
1181 {
1182 ng = new SecureRandom();
1183 }
1184 catch ( Throwable t )
1185 {
1186 // fall back to Random
1187 ng = new Random();
1188 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001189 }
1190
1191 byte[] randomBytes = new byte[16];
1192 ng.nextBytes( randomBytes );
1193 randomBytes[6] &= 0x0f; /* clear version */
1194 randomBytes[6] |= 0x40; /* set to version 4 */
1195 randomBytes[8] &= 0x3f; /* clear variant */
1196 randomBytes[8] |= 0x80; /* set to IETF variant */
1197
1198 StringBuffer buf = new StringBuffer( factoryPid.length() + 1 + 36 );
1199
1200 // prefix the new pid with the factory pid
1201 buf.append( factoryPid ).append( "." );
1202
1203 // serialize the UUID into the buffer
1204 for ( int i = 0; i < randomBytes.length; i++ )
1205 {
1206
1207 if ( i == 4 || i == 6 || i == 8 || i == 10 )
1208 {
1209 buf.append( '-' );
1210 }
1211
1212 int val = randomBytes[i] & 0xff;
1213 buf.append( Integer.toHexString( val >> 4 ) );
1214 buf.append( Integer.toHexString( val & 0xf ) );
1215 }
1216
1217 return buf.toString();
1218 }
1219
1220
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001221 public boolean isLogEnabled( int level )
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001222 {
1223 return level <= logLevel;
1224 }
1225
1226
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001227 public void log( int level, String format, Object[] args )
Felix Meschberger4f269292011-10-21 13:52:31 +00001228 {
1229 if ( isLogEnabled( level ) )
1230 {
1231 Throwable throwable = null;
1232 String message = format;
1233
1234 if ( args != null && args.length > 0 )
1235 {
1236 if ( args[args.length - 1] instanceof Throwable )
1237 {
1238 throwable = ( Throwable ) args[args.length - 1];
1239 }
1240 message = MessageFormat.format( format, args );
1241 }
1242
1243 log( level, message, throwable );
1244 }
1245 }
1246
1247
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001248 public void log( int level, String message, Throwable t )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001249 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001250 // log using the LogService if available
Felix Meschberger85b355d2007-08-31 07:17:38 +00001251 Object log = logTracker.getService();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001252 if ( log != null )
1253 {
Felix Meschbergerb4f83e42009-01-15 08:53:36 +00001254 ( ( LogService ) log ).log( getServiceReference(), level, message, t );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001255 return;
1256 }
1257
Felix Meschberger08282c32009-01-28 07:01:55 +00001258 // Otherwise only log if more serious than the configured level
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001259 if ( isLogEnabled( level ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001260 {
Felix Meschberger08282c32009-01-28 07:01:55 +00001261 String code;
1262 switch ( level )
1263 {
1264 case LogService.LOG_INFO:
1265 code = "*INFO *";
1266 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001267
Felix Meschberger08282c32009-01-28 07:01:55 +00001268 case LogService.LOG_WARNING:
1269 code = "*WARN *";
1270 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001271
Felix Meschberger08282c32009-01-28 07:01:55 +00001272 case LogService.LOG_ERROR:
1273 code = "*ERROR*";
1274 break;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001275
Felix Meschberger08282c32009-01-28 07:01:55 +00001276 case LogService.LOG_DEBUG:
1277 default:
1278 code = "*DEBUG*";
1279 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001280
Felix Meschberger08282c32009-01-28 07:01:55 +00001281 System.err.println( code + " " + message );
1282 if ( t != null )
1283 {
1284 t.printStackTrace( System.err );
1285 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001286 }
1287 }
1288
Felix Meschberger851c6412009-08-16 18:43:26 +00001289
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001290 public static String toString( ServiceReference ref )
Felix Meschberger41cce522009-08-19 05:54:40 +00001291 {
1292 String[] ocs = ( String[] ) ref.getProperty( "objectClass" );
Felix Meschberger382a19b2012-07-03 09:45:14 +00001293 StringBuffer buf = new StringBuffer( "[" );
Felix Meschberger41cce522009-08-19 05:54:40 +00001294 for ( int i = 0; i < ocs.length; i++ )
1295 {
Felix Meschberger382a19b2012-07-03 09:45:14 +00001296 buf.append( ocs[i] );
Felix Meschberger41cce522009-08-19 05:54:40 +00001297 if ( i < ocs.length - 1 )
Felix Meschberger382a19b2012-07-03 09:45:14 +00001298 buf.append( ", " );
Felix Meschberger41cce522009-08-19 05:54:40 +00001299 }
1300
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001301 buf.append( ", id=" ).append( ref.getProperty( Constants.SERVICE_ID ) );
1302
1303 Bundle provider = ref.getBundle();
1304 if ( provider != null )
1305 {
1306 buf.append( ", bundle=" ).append( provider.getBundleId() );
Felix Meschberger0135b322011-11-16 12:30:22 +00001307 buf.append( '/' ).append( provider.getLocation() );
Felix Meschbergerdc8a5532011-02-18 13:11:03 +00001308 }
1309 else
1310 {
1311 buf.append( ", unregistered" );
1312 }
1313
1314 buf.append( "]" );
1315 return buf.toString();
Felix Meschberger41cce522009-08-19 05:54:40 +00001316 }
1317
Felix Meschbergerce67d732009-08-20 06:26:35 +00001318
Felix Meschberger007c50e2011-10-20 12:39:38 +00001319 /**
1320 * Checks whether the bundle is allowed to receive the configuration
1321 * with the given location binding.
1322 * <p>
1323 * This method implements the logic defined CM 1.4 / 104.4.1:
1324 * <ul>
1325 * <li>If the location is <code>null</code> (the configuration is not
1326 * bound yet), assume the bundle is allowed</li>
1327 * <li>If the location is a single location (no leading "?"), require
1328 * the bundle's location to match</li>
1329 * <li>If the location is a multi-location (leading "?"), assume the
1330 * bundle is allowed if there is no security manager. If there is a
1331 * security manager, check whether the bundle has "target" permission
1332 * on this location.</li>
1333 * </ul>
1334 */
1335 boolean canReceive( final Bundle bundle, final String location )
1336 {
1337 if ( location == null )
1338 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001339 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration=(unbound)", new Object[]
Felix Meschberger61207232011-11-17 10:06:45 +00001340 { bundle.getLocation() } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001341 return true;
1342 }
1343 else if ( location.startsWith( "?" ) )
1344 {
1345 // multi-location
1346 if ( System.getSecurityManager() != null )
1347 {
Felix Meschberger61207232011-11-17 10:06:45 +00001348 final boolean hasPermission = bundle.hasPermission( new ConfigurationPermission( location,
1349 ConfigurationPermission.TARGET ) );
1350 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2} (SecurityManager check)",
1351 new Object[]
1352 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1353 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001354 }
Felix Meschberger61207232011-11-17 10:06:45 +00001355
1356 log( LogService.LOG_DEBUG, "canReceive=true; bundle={0}; configuration={1} (no SecurityManager)",
1357 new Object[]
1358 { bundle.getLocation(), location } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001359 return true;
1360 }
1361 else
1362 {
1363 // single location, must match
Felix Meschberger61207232011-11-17 10:06:45 +00001364 final boolean hasPermission = location.equals( bundle.getLocation() );
1365 log( LogService.LOG_DEBUG, "canReceive={0}: bundle={1}; configuration={2}", new Object[]
1366 { new Boolean( hasPermission ), bundle.getLocation(), location } );
1367 return hasPermission;
Felix Meschberger007c50e2011-10-20 12:39:38 +00001368 }
1369 }
1370
Felix Meschberger61207232011-11-17 10:06:45 +00001371
Felix Meschberger007c50e2011-10-20 12:39:38 +00001372 // ---------- inner classes
1373
Felix Meschberger007c50e2011-10-20 12:39:38 +00001374 /**
1375 * The <code>ManagedServiceUpdate</code> updates a freshly registered
1376 * <code>ManagedService</code> with a specific configuration. If a
1377 * ManagedService is registered with multiple PIDs an instance of this
1378 * class is used for each registered PID.
1379 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001380 private class ManagedServiceUpdate implements Runnable
1381 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001382 private final String[] pids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001383
Felix Meschberger41cce522009-08-19 05:54:40 +00001384 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001385
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001386 private final ConfigurationMap<?> configs;
1387
1388
1389 ManagedServiceUpdate( String[] pids, ServiceReference sr, ConfigurationMap<?> configs )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001390 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001391 this.pids = pids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001392 this.sr = sr;
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001393 this.configs = configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001394 }
1395
1396
1397 public void run()
1398 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001399 for ( String pid : this.pids )
1400 {
1401 try
1402 {
1403 final ConfigurationImpl config = getTargetedConfiguration( pid, this.sr );
1404 provide( pid, config );
1405 }
1406 catch ( IOException ioe )
1407 {
1408 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1409 { pid, ioe } );
1410 }
1411 catch ( Exception e )
1412 {
1413 log( LogService.LOG_ERROR, "Unexpected problem providing configuration {0} to service {1}",
1414 new Object[]
1415 { pid, ConfigurationManager.toString( this.sr ), e } );
1416 }
1417 }
1418 }
Felix Meschbergercb46b9e2009-08-31 14:33:15 +00001419
Felix Meschberger273985f2012-07-05 12:28:06 +00001420
1421 private void provide(final String servicePid, final ConfigurationImpl config)
1422 {
1423 // check configuration
1424 final TargetedPID configPid;
1425 final Dictionary properties;
1426 final long revision;
Felix Meschberger41cce522009-08-19 05:54:40 +00001427 if ( config != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001428 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001429 synchronized ( config )
Felix Meschberger41243192009-01-14 19:59:58 +00001430 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001431 configPid = config.getPid();
1432 properties = config.getProperties( true );
1433 revision = config.getRevision();
Felix Meschberger41243192009-01-14 19:59:58 +00001434 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001435 }
1436 else
1437 {
Felix Meschberger2941ef92007-08-20 13:15:16 +00001438 // 104.5.3 ManagedService.updated must be called with null
1439 // if no configuration is available
Felix Meschberger273985f2012-07-05 12:28:06 +00001440 configPid = new TargetedPID( servicePid );
Felix Meschberger41cce522009-08-19 05:54:40 +00001441 properties = null;
Felix Meschberger273985f2012-07-05 12:28:06 +00001442 revision = -1;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001443 }
1444
Felix Meschberger273985f2012-07-05 12:28:06 +00001445 log( LogService.LOG_DEBUG, "Updating service {0} with configuration {1}@{2}", new Object[]
1446 { servicePid, configPid, new Long( revision ) } );
1447
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001448 managedServiceTracker.provideConfiguration( sr, configPid, null, properties, revision, this.configs );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001449 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001450
Felix Meschberger432e3872008-03-07 14:58:57 +00001451 public String toString()
1452 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001453 return "ManagedService Update: pid=" + Arrays.asList( pids );
Felix Meschberger432e3872008-03-07 14:58:57 +00001454 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001455 }
1456
Felix Meschberger007c50e2011-10-20 12:39:38 +00001457 /**
1458 * The <code>ManagedServiceFactoryUpdate</code> updates a freshly
1459 * registered <code>ManagedServiceFactory</code> with a specific
1460 * configuration. If a ManagedServiceFactory is registered with
1461 * multiple PIDs an instance of this class is used for each registered
1462 * PID.
1463 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001464 private class ManagedServiceFactoryUpdate implements Runnable
1465 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001466 private final String[] factoryPids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001467
Felix Meschberger41cce522009-08-19 05:54:40 +00001468 private final ServiceReference sr;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001469
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001470 private final ConfigurationMap<?> configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001471
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001472
1473 ManagedServiceFactoryUpdate( String[] factoryPids, ServiceReference sr, final ConfigurationMap<?> configs )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001474 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001475 this.factoryPids = factoryPids;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001476 this.sr = sr;
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001477 this.configs = configs;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001478 }
1479
1480
1481 public void run()
1482 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001483 for ( String factoryPid : this.factoryPids )
1484 {
1485
1486 List<Factory> factories = null;
1487 try
1488 {
1489 factories = getTargetedFactories( factoryPid, sr );
1490 for ( Factory factory : factories )
1491 {
1492 for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
1493 {
1494 final String pid = ( String ) pi.next();
1495 ConfigurationImpl cfg;
1496 try
1497 {
1498 cfg = getConfiguration( pid );
1499 }
1500 catch ( IOException ioe )
1501 {
1502 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1503 { pid, ioe } );
1504 continue;
1505 }
1506
1507 // sanity check on the configuration
1508 if ( cfg == null )
1509 {
1510 log( LogService.LOG_ERROR,
1511 "Configuration {0} referred to by factory {1} does not exist", new Object[]
1512 { pid, factoryPid } );
1513 factory.removePID( pid );
1514 factory.storeSilently();
1515 continue;
1516 }
1517 else if ( cfg.isNew() )
1518 {
1519 // Configuration has just been created but not yet updated
1520 // we currently just ignore it and have the update mechanism
1521 // provide the configuration to the ManagedServiceFactory
1522 // As of FELIX-612 (not storing new factory configurations)
1523 // this should not happen. We keep this for added stability
1524 // but raise the logging level to error.
1525 log( LogService.LOG_ERROR, "Ignoring new configuration pid={0}", new Object[]
1526 { pid } );
1527 continue;
1528 }
1529
1530 /*
1531 * this code would catch targeted factory PIDs;
1532 * since this is not expected any way, we can
1533 * leave this out
1534 */
1535 /*
1536 else if ( !factoryPid.equals( cfg.getFactoryPid() ) )
1537 {
1538 log( LogService.LOG_ERROR,
1539 "Configuration {0} referred to by factory {1} seems to belong to factory {2}",
1540 new Object[]
1541 { pid, factoryPid, cfg.getFactoryPid() } );
1542 factory.removePID( pid );
1543 factory.storeSilently();
1544 continue;
1545 }
1546 */
1547
1548 provide( factoryPid, cfg );
1549 }
1550 }
1551 }
1552 catch ( IOException ioe )
1553 {
1554 log( LogService.LOG_ERROR, "Cannot get factory mapping for factory PID {0}", new Object[]
1555 { factoryPid, ioe } );
1556 }
1557 }
1558 }
1559
1560
1561 private void provide(final String factoryPid, final ConfigurationImpl config) {
1562
1563 final Dictionary rawProperties;
1564 final long revision;
1565 synchronized ( config )
1566 {
1567 rawProperties = config.getProperties( true );
1568 revision = config.getRevision();
1569 }
1570
1571 log( LogService.LOG_DEBUG, "Updating service {0} with configuration {1}/{2}@{3}", new Object[]
1572 { factoryPid, config.getFactoryPid(), config.getPid(), new Long( revision ) } );
1573
1574 // CM 1.4 / 104.13.2.1
1575 final Bundle serviceBundle = this.sr.getBundle();
Felix Meschberger41243192009-01-14 19:59:58 +00001576 if ( serviceBundle == null )
1577 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001578 log(
1579 LogService.LOG_INFO,
1580 "ManagedServiceFactory for factory PID {0} seems to already have been unregistered, not updating with factory",
1581 new Object[]
1582 { factoryPid } );
Felix Meschberger41243192009-01-14 19:59:58 +00001583 return;
1584 }
1585
Felix Meschberger273985f2012-07-05 12:28:06 +00001586 if ( !canReceive( serviceBundle, config.getBundleLocation() ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001587 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001588 log( LogService.LOG_ERROR,
1589 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001590 new Object[]
Felix Meschberger273985f2012-07-05 12:28:06 +00001591 { config.getPid(), ConfigurationManager.toString( sr ), config.getBundleLocation() } );
1592
1593 // no service, really, bail out
1594 return;
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001595 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001596
1597 // 104.4.2 Dynamic Binding
1598 config.tryBindLocation( serviceBundle.getLocation() );
1599
1600 // update the service with the configuration (if non-null)
1601 if ( rawProperties != null )
Felix Meschbergerf768ef92012-01-29 13:59:32 +00001602 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001603 log( LogService.LOG_DEBUG, "{0}: Updating configuration pid={1}", new Object[]
1604 { ConfigurationManager.toString( sr ), config.getPid() } );
1605 managedServiceFactoryTracker.provideConfiguration( sr, config.getPid(), config.getFactoryPid(),
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001606 rawProperties, revision, this.configs );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001607 }
1608 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001609
1610
Felix Meschberger432e3872008-03-07 14:58:57 +00001611 public String toString()
1612 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001613 return "ManagedServiceFactory Update: factoryPid=" + Arrays.asList( this.factoryPids );
Felix Meschberger432e3872008-03-07 14:58:57 +00001614 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001615 }
1616
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001617 private abstract class ConfigurationProvider<T> implements Runnable
1618 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001619
1620 protected final ConfigurationImpl config;
1621 protected final long revision;
1622 protected final Dictionary<String, ?> properties;
Felix Meschbergerfffde292012-11-18 18:02:20 +00001623 private BaseTracker<T> helper;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001624
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001625
1626 protected ConfigurationProvider( final ConfigurationImpl config )
1627 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001628 synchronized ( config )
1629 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001630 this.config = config;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001631 this.revision = config.getRevision();
1632 this.properties = config.getProperties( true );
1633 }
1634 }
1635
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001636
1637 protected TargetedPID getTargetedServicePid()
1638 {
1639 final TargetedPID factoryPid = this.config.getFactoryPid();
1640 if ( factoryPid != null )
1641 {
1642 return factoryPid;
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001643 }
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001644 return this.config.getPid();
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001645 }
Felix Meschberger273985f2012-07-05 12:28:06 +00001646
1647
Felix Meschbergerfffde292012-11-18 18:02:20 +00001648 protected BaseTracker<T> getHelper()
1649 {
1650 if ( this.helper == null )
1651 {
1652 this.helper = ( BaseTracker<T> ) ( ( this.config.getFactoryPid() == null ) ? ConfigurationManager.this.managedServiceTracker
1653 : ConfigurationManager.this.managedServiceFactoryTracker );
1654 }
1655 return this.helper;
1656 }
1657
1658
Felix Meschberger273985f2012-07-05 12:28:06 +00001659 protected boolean provideReplacement( ServiceReference<T> sr )
1660 {
1661 if ( this.config.getFactoryPid() == null )
1662 {
1663 try
1664 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001665 final String configPidString = this.getHelper().getServicePid( sr, this.config.getPid() );
Felix Meschberger1ff5c532012-07-08 18:23:08 +00001666 final ConfigurationImpl rc = getTargetedConfiguration( configPidString, sr );
Felix Meschberger273985f2012-07-05 12:28:06 +00001667 if ( rc != null )
1668 {
1669 final TargetedPID configPid;
1670 final Dictionary properties;
1671 final long revision;
Felix Meschbergercd5195f2012-07-05 17:17:45 +00001672 synchronized ( rc )
Felix Meschberger273985f2012-07-05 12:28:06 +00001673 {
Felix Meschbergercd5195f2012-07-05 17:17:45 +00001674 configPid = rc.getPid();
1675 properties = rc.getProperties( true );
1676 revision = rc.getRevision();
Felix Meschberger273985f2012-07-05 12:28:06 +00001677 }
1678
Felix Meschbergerfffde292012-11-18 18:02:20 +00001679 this.getHelper().provideConfiguration( sr, configPid, null, properties, -revision, null );
Felix Meschberger273985f2012-07-05 12:28:06 +00001680
1681 return true;
1682 }
1683 }
1684 catch ( IOException ioe )
1685 {
1686 log( LogService.LOG_ERROR, "Error loading configuration for {0}", new Object[]
1687 { this.config.getPid(), ioe } );
1688 }
1689 catch ( Exception e )
1690 {
1691 log( LogService.LOG_ERROR, "Unexpected problem providing configuration {0} to service {1}",
1692 new Object[]
1693 { this.config.getPid(), ConfigurationManager.toString( sr ), e } );
1694 }
1695 }
1696
1697 // factory or no replacement available
1698 return false;
1699 }
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001700 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001701
1702 /**
1703 * The <code>UpdateConfiguration</code> is used to update
1704 * <code>ManagedService[Factory]</code> services with the configuration
1705 * they are subscribed to. This may cause the configuration to be
1706 * supplied to multiple services.
1707 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001708 private class UpdateConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001709 {
1710
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001711 UpdateConfiguration( final ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001712 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001713 super( config );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001714 }
1715
1716
1717 public void run()
1718 {
Felix Meschberger61207232011-11-17 10:06:45 +00001719 log( LogService.LOG_DEBUG, "Updating configuration {0} to revision #{1}", new Object[]
1720 { config.getPid(), new Long( revision ) } );
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001721
Felix Meschbergerfffde292012-11-18 18:02:20 +00001722 final List<ServiceReference<?>> srList = this.getHelper().getServices( getTargetedServicePid() );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001723 if ( !srList.isEmpty() )
Felix Meschberger41cce522009-08-19 05:54:40 +00001724 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001725 // optionally bind dynamically to the first service
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001726 config.tryBindLocation( srList.get( 0 ).getBundle().getLocation() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001727
1728 final String configBundleLocation = config.getBundleLocation();
1729
1730 // provide configuration to all services from the
1731 // correct bundle
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001732 for (ServiceReference<?> ref : srList)
Felix Meschberger41cce522009-08-19 05:54:40 +00001733 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001734 final Bundle refBundle = ref.getBundle();
1735 if ( refBundle == null )
Felix Meschberger41cce522009-08-19 05:54:40 +00001736 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001737 log( LogService.LOG_DEBUG,
1738 "Service {0} seems to be unregistered concurrently (not providing configuration)",
1739 new Object[]
1740 { ConfigurationManager.toString( ref ) } );
1741 }
1742 else if ( canReceive( refBundle, configBundleLocation ) )
1743 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001744 this.getHelper().provideConfiguration( ref, this.config.getPid(), this.config.getFactoryPid(),
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001745 this.properties, this.revision, null );
Felix Meschberger2444da62011-11-17 11:17:50 +00001746 }
1747 else
1748 {
1749 // CM 1.4 / 104.13.2.2
Felix Meschberger4f269292011-10-21 13:52:31 +00001750 log( LogService.LOG_ERROR,
1751 "Cannot use configuration {0} for {1}: No visibility to configuration bound to {2}",
1752 new Object[]
1753 { config.getPid(), ConfigurationManager.toString( ref ), configBundleLocation } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001754 }
1755
Felix Meschberger41cce522009-08-19 05:54:40 +00001756 }
Felix Meschberger6f5b69e2009-08-19 09:39:21 +00001757 }
Felix Meschberger137ee722011-11-16 09:51:59 +00001758 else if ( isLogEnabled( LogService.LOG_DEBUG ) )
1759 {
Felix Meschberger1ee888d2011-11-16 12:42:57 +00001760 log( LogService.LOG_DEBUG, "No ManagedService[Factory] registered for updates to configuration {0}",
Felix Meschberger137ee722011-11-16 09:51:59 +00001761 new Object[]
1762 { config.getPid() } );
1763 }
Felix Meschberger41cce522009-08-19 05:54:40 +00001764 }
1765
1766
Felix Meschberger432e3872008-03-07 14:58:57 +00001767 public String toString()
1768 {
1769 return "Update: pid=" + config.getPid();
1770 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001771 }
1772
Felix Meschberger007c50e2011-10-20 12:39:38 +00001773
1774 /**
1775 * The <code>DeleteConfiguration</code> class is used to inform
1776 * <code>ManagedService[Factory]</code> services of a configuration
1777 * being deleted.
1778 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001779 private class DeleteConfiguration extends ConfigurationProvider
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001780 {
Felix Meschberger66423332007-08-22 08:46:34 +00001781
Felix Meschbergerc12db8c2009-08-19 06:43:59 +00001782 private final String configLocation;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001783
1784
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001785 DeleteConfiguration( ConfigurationImpl config )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001786 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001787 /*
1788 * NOTE: We keep the configuration because it might be cleared just
1789 * after calling this method. The pid and factoryPid fields are
1790 * final and cannot be reset.
1791 */
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001792 super(config);
Felix Meschberger007c50e2011-10-20 12:39:38 +00001793 this.configLocation = config.getBundleLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001794 }
1795
1796
1797 public void run()
1798 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001799 List<ServiceReference<?>> srList = this.getHelper().getServices( getTargetedServicePid() );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001800 if ( !srList.isEmpty() )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001801 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001802 for (ServiceReference<?> sr : srList)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001803 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001804 final Bundle srBundle = sr.getBundle();
1805 if ( srBundle == null )
1806 {
1807 log( LogService.LOG_DEBUG,
1808 "Service {0} seems to be unregistered concurrently (not removing configuration)",
1809 new Object[]
1810 { ConfigurationManager.toString( sr ) } );
1811 }
1812 else if ( canReceive( srBundle, configLocation ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001813 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001814 // revoke configuration unless a replacement
1815 // configuration can be provided
1816 if ( !this.provideReplacement( sr ) )
1817 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001818 this.getHelper().removeConfiguration( sr, this.config.getPid(), this.config.getFactoryPid() );
Felix Meschberger273985f2012-07-05 12:28:06 +00001819 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001820 }
Felix Meschberger2444da62011-11-17 11:17:50 +00001821 else
1822 {
1823 // CM 1.4 / 104.13.2.2
1824 log( LogService.LOG_ERROR,
1825 "Cannot remove configuration {0} for {1}: No visibility to configuration bound to {2}",
1826 new Object[]
1827 { config.getPid(), ConfigurationManager.toString( sr ), configLocation } );
1828 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001829 }
1830 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001831
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001832 final TargetedPID factoryPid = config.getFactoryPid();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001833 if ( factoryPid != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001834 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001835 // remove the pid from the factory
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001836 final String pid = config.getPidString();
Felix Meschberger007c50e2011-10-20 12:39:38 +00001837 try
1838 {
Felix Meschbergerc0894f32012-07-04 08:09:55 +00001839 Factory factory = getOrCreateFactory( factoryPid.toString() );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001840 factory.removePID( pid );
1841 factory.store();
1842 }
1843 catch ( IOException ioe )
1844 {
Felix Meschberger4f269292011-10-21 13:52:31 +00001845 log( LogService.LOG_ERROR, "Failed removing {0} from the factory {1}", new Object[]
1846 { pid, factoryPid, ioe } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001847 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001848 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001849 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00001850
Felix Meschberger432e3872008-03-07 14:58:57 +00001851 public String toString()
1852 {
Felix Meschbergerce67d732009-08-20 06:26:35 +00001853 return "Delete: pid=" + config.getPid();
Felix Meschberger432e3872008-03-07 14:58:57 +00001854 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001855 }
1856
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001857 private class LocationChanged extends ConfigurationProvider
Felix Meschberger007c50e2011-10-20 12:39:38 +00001858 {
Felix Meschberger007c50e2011-10-20 12:39:38 +00001859 private final String oldLocation;
1860
1861
1862 LocationChanged( ConfigurationImpl config, String oldLocation )
1863 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001864 super( config );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001865 this.oldLocation = oldLocation;
1866 }
1867
1868
1869 public void run()
1870 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001871 List<ServiceReference<?>> srList = this.getHelper().getServices( getTargetedServicePid() );
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001872 if ( !srList.isEmpty() )
Felix Meschberger007c50e2011-10-20 12:39:38 +00001873 {
Felix Meschberger63e7ab12012-07-02 14:10:43 +00001874 for (final ServiceReference<?> sr : srList)
Felix Meschberger007c50e2011-10-20 12:39:38 +00001875 {
Felix Meschberger2444da62011-11-17 11:17:50 +00001876 final Bundle srBundle = sr.getBundle();
1877 if ( srBundle == null )
1878 {
1879 log( LogService.LOG_DEBUG,
1880 "Service {0} seems to be unregistered concurrently (not processing)", new Object[]
1881 { ConfigurationManager.toString( sr ) } );
1882 continue;
1883 }
1884
1885 final boolean wasVisible = canReceive( srBundle, oldLocation );
1886 final boolean isVisible = canReceive( srBundle, config.getBundleLocation() );
1887
1888 // make sure the config is dynamically bound to the first
1889 // service if the config has been unbound causing this update
1890 if ( isVisible )
1891 {
1892 config.tryBindLocation( srBundle.getLocation() );
1893 }
1894
Felix Meschberger007c50e2011-10-20 12:39:38 +00001895 if ( wasVisible && !isVisible )
1896 {
Felix Meschberger273985f2012-07-05 12:28:06 +00001897 // revoke configuration unless a replacement
1898 // configuration can be provided
1899 if ( !this.provideReplacement( sr ) )
1900 {
Felix Meschbergerfffde292012-11-18 18:02:20 +00001901 this.getHelper().removeConfiguration( sr, this.config.getPid(), this.config.getFactoryPid() );
Felix Meschberger273985f2012-07-05 12:28:06 +00001902 log( LogService.LOG_DEBUG, "Configuration {0} revoked from {1} (no more visibility)",
1903 new Object[]
1904 { config.getPid(), ConfigurationManager.toString( sr ) } );
1905 }
Felix Meschberger007c50e2011-10-20 12:39:38 +00001906 }
1907 else if ( !wasVisible && isVisible )
1908 {
1909 // call updated method
Felix Meschbergerfffde292012-11-18 18:02:20 +00001910 this.getHelper().provideConfiguration( sr, this.config.getPid(), this.config.getFactoryPid(),
Felix Meschberger3cbf4652012-10-18 06:49:39 +00001911 this.properties, this.revision, null );
Felix Meschberger4f269292011-10-21 13:52:31 +00001912 log( LogService.LOG_DEBUG, "Configuration {0} provided to {1} (new visibility)", new Object[]
1913 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger35658d52011-10-20 21:43:58 +00001914 }
Felix Meschberger4f269292011-10-21 13:52:31 +00001915 else
Felix Meschberger35658d52011-10-20 21:43:58 +00001916 {
1917 // same visibility as before
Felix Meschberger4f269292011-10-21 13:52:31 +00001918 log( LogService.LOG_DEBUG, "Unmodified visibility to configuration {0} for {1}", new Object[]
1919 { config.getPid(), ConfigurationManager.toString( sr ) } );
Felix Meschberger007c50e2011-10-20 12:39:38 +00001920 }
1921 }
1922 }
1923 }
1924
1925
1926 public String toString()
1927 {
1928 return "Location Changed (pid=" + config.getPid() + "): " + oldLocation + " ==> "
1929 + config.getBundleLocation();
1930 }
1931 }
1932
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001933 private class FireConfigurationEvent implements Runnable
1934 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001935 private final int type;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001936
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001937 private final String pid;
Felix Meschberger2fd5b582007-12-10 10:32:29 +00001938
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001939 private final String factoryPid;
1940
1941 private final ServiceReference[] listenerReferences;
1942
1943 private final ConfigurationListener[] listeners;
1944
1945 private final Bundle[] listenerProvider;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001946
Felix Meschberger0770cad2012-06-11 12:36:52 +00001947 private ConfigurationEvent event;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001948
Felix Meschbergere94b1572012-07-14 11:59:29 +00001949 private FireConfigurationEvent( final ServiceTracker listenerTracker, final int type, final String pid, final String factoryPid)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001950 {
1951 this.type = type;
Felix Meschberger66423332007-08-22 08:46:34 +00001952 this.pid = pid;
1953 this.factoryPid = factoryPid;
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001954
Felix Meschbergere94b1572012-07-14 11:59:29 +00001955 final ServiceReference[] srs = listenerTracker.getServiceReferences();
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001956 if ( srs == null || srs.length == 0 )
1957 {
1958 this.listenerReferences = null;
1959 this.listeners = null;
1960 this.listenerProvider = null;
1961 }
1962 else
1963 {
1964 this.listenerReferences = srs;
1965 this.listeners = new ConfigurationListener[srs.length];
1966 this.listenerProvider = new Bundle[srs.length];
1967 for ( int i = 0; i < srs.length; i++ )
1968 {
Felix Meschbergere94b1572012-07-14 11:59:29 +00001969 this.listeners[i] = ( ConfigurationListener ) listenerTracker.getService( srs[i] );
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001970 this.listenerProvider[i] = srs[i].getBundle();
1971 }
1972 }
1973 }
1974
1975
1976 boolean hasConfigurationEventListeners()
1977 {
1978 return this.listenerReferences != null;
1979 }
1980
1981
1982 String getTypeName()
1983 {
1984 switch ( type )
1985 {
1986 case ConfigurationEvent.CM_DELETED:
1987 return "CM_DELETED";
1988 case ConfigurationEvent.CM_UPDATED:
1989 return "CM_UPDATED";
Felix Meschberger007c50e2011-10-20 12:39:38 +00001990 case ConfigurationEvent.CM_LOCATION_CHANGED:
1991 return "CM_LOCATION_CHANGED";
Felix Meschberger9967fbb2010-08-25 18:13:25 +00001992 default:
1993 return "<UNKNOWN(" + type + ")>";
1994 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00001995 }
1996
1997
1998 public void run()
1999 {
Felix Meschberger9967fbb2010-08-25 18:13:25 +00002000 for ( int i = 0; i < listeners.length; i++ )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002001 {
Felix Meschberger0770cad2012-06-11 12:36:52 +00002002 sendEvent( i );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002003 }
2004 }
Felix Meschberger5dfaa962009-08-14 19:26:01 +00002005
Felix Meschberger0770cad2012-06-11 12:36:52 +00002006
Felix Meschberger432e3872008-03-07 14:58:57 +00002007 public String toString()
2008 {
2009 return "Fire ConfigurationEvent: pid=" + pid;
2010 }
Felix Meschberger0770cad2012-06-11 12:36:52 +00002011
2012
2013 private ConfigurationEvent getConfigurationEvent()
2014 {
2015 if ( event == null )
2016 {
2017 this.event = new ConfigurationEvent( getServiceReference(), type, factoryPid, pid );
2018 }
2019 return event;
2020 }
2021
2022
2023 private void sendEvent( final int serviceIndex )
2024 {
2025 if ( listenerProvider[serviceIndex].getState() == Bundle.ACTIVE && this.listeners[serviceIndex] != null )
2026 {
2027 log( LogService.LOG_DEBUG, "Sending {0} event for {1} to {2}", new Object[]
2028 { getTypeName(), pid, ConfigurationManager.toString( listenerReferences[serviceIndex] ) } );
2029
2030 try
2031 {
2032 listeners[serviceIndex].configurationEvent( getConfigurationEvent() );
2033 }
2034 catch ( Throwable t )
2035 {
2036 log( LogService.LOG_ERROR, "Unexpected problem delivering configuration event to {0}", new Object[]
2037 { ConfigurationManager.toString( listenerReferences[serviceIndex] ), t } );
2038 }
2039 finally
2040 {
2041 this.listeners[serviceIndex] = null;
2042 }
2043 }
2044 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002045 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +00002046}
Felix Meschberger273985f2012-07-05 12:28:06 +00002047