blob: 68f9faaf1430a99a6a7780ff39b997a03a367bb3 [file] [log] [blame]
Carsten Ziegeler6c6f25b2007-08-15 10:04:02 +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
22import java.io.IOException;
23import java.util.Dictionary;
24import java.util.Hashtable;
25
26import org.apache.felix.cm.PersistenceManager;
27import org.osgi.framework.Constants;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000028import org.osgi.service.cm.Configuration;
29import org.osgi.service.cm.ConfigurationAdmin;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000030import org.osgi.service.log.LogService;
Carsten Ziegelereb80d512007-08-15 11:17:41 +000031
Felix Meschberger93c409a2009-01-19 10:47:59 +000032
Carsten Ziegelereb80d512007-08-15 11:17:41 +000033/**
Felix Meschberger93c409a2009-01-19 10:47:59 +000034 * The <code>ConfigurationImpl</code> is the backend implementation of the
35 * Configuration Admin Service Specification <i>Configuration object</i>
36 * (section 104.4). Instances of this class are shared by multiple instances of
37 * the {@link ConfigurationAdapter} class, whose instances are actually returned
38 * to clients.
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000039 */
Felix Meschbergeref470042009-08-19 05:52:41 +000040class ConfigurationImpl extends ConfigurationBase
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000041{
42
Felix Meschbergerfd52e312009-08-29 19:44:58 +000043 /*
44 * Concurrency note: There is a slight (but real) chance of a race condition
45 * between a configuration update and a ManagedService[Factory] registration.
46 * Per the specification a ManagedService must be called with configuration
47 * or null when registered and a ManagedService must be called with currently
48 * existing configuration when registered. Also the ManagedService[Factory]
49 * must be updated when the configuration is updated.
50 *
51 * Consider now this situation of two threads T1 and T2:
52 *
53 * T1. create and update configuration
54 * ConfigurationImpl.update persists configuration and sets field
55 * Thread preempted
56 *
57 * T2. ManagedServiceUpdate constructor reads configuration
58 * Uses configuration already persisted by T1 for update
59 * Schedules task to update service with the configuration
60 *
61 * T1. Runs again creating the UpdateConfiguration task with the
62 * configuration persisted before being preempted
63 * Schedules task to update service
64 *
65 * Update Thread:
66 * Updates ManagedService with configuration prepared by T2
67 * Updates ManagedService with configuration prepared by T1
68 *
69 * The correct behaviour would be here, that the second call to update
70 * would not take place.
71 *
72 * This concurrency safety is implemented with the help of the
73 * lastModificationTime field updated by the configure(Dictionary) method
74 * when setting the properties field and the lastUpdatedTime field updated
75 * in the Update Thread after calling the update(Dictionary) method of
76 * the ManagedService[Factory] service.
77 *
78 * The UpdateConfiguration task compares the lastModificationTime to the
79 * lastUpdateTime. If the configuration has been modified after being
80 * updated the last time, it is updated in the ManagedService[Factory]. If
81 * the configuration has already been updated since being modified (as in
82 * the case above), the UpdateConfiguration thread does not call the update
83 * method (but still sends the CM_UPDATED event).
84 *
85 * See also FELIX-1542.
86 */
87
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000088 /**
Felix Meschberger2941ef92007-08-20 13:15:16 +000089 * The name of a synthetic property stored in the persisted configuration
90 * data to indicate that the configuration data is new, that is created but
91 * never updated (value is "_felix_.cm.newConfiguration").
92 * <p>
93 * This special property is stored by the
94 * {@link #ConfigurationImpl(ConfigurationManager, PersistenceManager, String, String, String)}
95 * constructor, when the configuration is first created and persisted and is
96 * interpreted by the
97 * {@link #ConfigurationImpl(ConfigurationManager, PersistenceManager, Dictionary)}
98 * method when the configuration data is loaded in a new object.
99 * <p>
100 * The goal of this property is to keep the information on whether
101 * configuration data is new (but persisted as per the spec) or has already
102 * been assigned with possible no data.
103 */
104 private static final String CONFIGURATION_NEW = "_felix_.cm.newConfiguration";
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000105
Felix Meschberger2941ef92007-08-20 13:15:16 +0000106 /**
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000107 * The factory serviceReference PID of this configuration or <code>null</code> if this
108 * is not a factory configuration.
109 */
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000110 private final String factoryPID;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000111
112 /**
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000113 * The configuration data of this configuration instance. This is a private
114 * copy of the properties of which a copy is made when the
Felix Meschbergeref470042009-08-19 05:52:41 +0000115 * {@link #getProperties()} method is called. This field is
116 * <code>null</code> if the configuration has been created and never been
117 * updated with acutal configuration properties.
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000118 */
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000119 private volatile CaseInsensitiveDictionary properties;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000120
Felix Meschbergerf4631322008-03-10 12:32:35 +0000121 /**
Felix Meschbergeref470042009-08-19 05:52:41 +0000122 * Flag indicating that this configuration has been deleted.
123 *
124 * @see #isDeleted()
Felix Meschbergerf4631322008-03-10 12:32:35 +0000125 */
Felix Meschbergeref470042009-08-19 05:52:41 +0000126 private volatile boolean isDeleted;
127
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000128 /**
129 * Time of last configuration properties update.
130 * This is intended to be managed by the {@link #configure(Dictionary)}
131 * method when setting the properties field.
132 * <p>
133 * This field is set to the current time upon construction and every time
134 * the {@link #configure(Dictionary)} method sets the {@link #properties}
135 * field.
136 */
137 private volatile long lastModificationTime;
138
139 /**
140 * Time of last submission of the configuration properties to the (or more)
141 * ManagedService[Factory] services this is managed by the update thread
142 * and must solely be handled on the Update Thread.
143 * <p>
144 * This field is initialized to -1 in the constructors and is set to the
145 * current time when the configuration properties are supplied to the
146 * ManagedService[Factory] in the Update Thread.
147 *
148 * @see #lastModificationTime
149 */
150 private volatile long lastUpdatedTime;
151
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000152
153 ConfigurationImpl( ConfigurationManager configurationManager, PersistenceManager persistenceManager,
154 Dictionary properties )
155 {
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000156 super( configurationManager, persistenceManager, ( String ) properties.remove( Constants.SERVICE_PID ),
157 ( String ) properties.remove( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000158
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000159 this.factoryPID = ( String ) properties.remove( ConfigurationAdmin.SERVICE_FACTORYPID );
Felix Meschbergeref470042009-08-19 05:52:41 +0000160 this.isDeleted = false;
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000161 this.lastUpdatedTime = -1;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000162
Felix Meschberger2941ef92007-08-20 13:15:16 +0000163 // set the properties internally
164 configureFromPersistence( properties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000165 }
166
167
168 ConfigurationImpl( ConfigurationManager configurationManager, PersistenceManager persistenceManager, String pid,
Felix Meschberger2941ef92007-08-20 13:15:16 +0000169 String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000170 {
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000171 super( configurationManager, persistenceManager, pid, bundleLocation );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000172
Felix Meschberger2941ef92007-08-20 13:15:16 +0000173 this.factoryPID = factoryPid;
Felix Meschbergeref470042009-08-19 05:52:41 +0000174 this.isDeleted = false;
Felix Meschberger2941ef92007-08-20 13:15:16 +0000175 this.properties = null;
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000176 this.lastModificationTime = System.currentTimeMillis();
177 this.lastUpdatedTime = -1;
Felix Meschberger2941ef92007-08-20 13:15:16 +0000178
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000179 // this is a new configuration object, store immediately unless
180 // the new configuration object is created from a factory, in which
181 // case the configuration is only stored when first updated
Felix Meschbergeref470042009-08-19 05:52:41 +0000182 if ( factoryPid == null )
183 {
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000184 Dictionary props = new Hashtable();
Felix Meschbergeref470042009-08-19 05:52:41 +0000185 setAutoProperties( props, true );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000186 props.put( CONFIGURATION_NEW, Boolean.TRUE );
187 persistenceManager.store( pid, props );
188 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000189 }
190
191
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000192 public void delete() throws IOException
193 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000194 this.isDeleted = true;
195 getPersistenceManager().delete( this.getPid() );
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000196 getConfigurationManager().setDynamicBundleLocation( this.getPid(), null );
197 getConfigurationManager().deleted( this );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000198 }
199
200
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000201 public String getPid()
202 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000203 return getBaseId();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000204 }
205
206
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000207 public String getFactoryPid()
208 {
Carsten Ziegelereb80d512007-08-15 11:17:41 +0000209 return factoryPID;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000210 }
211
212
Felix Meschbergera0903df2009-01-19 10:40:28 +0000213 /**
214 * Returns an optionally deep copy of the properties of this configuration
215 * instance.
216 * <p>
217 * This method returns a copy of the internal dictionary. If the
218 * <code>deepCopy</code> parameter is true array and collection values are
219 * copied into new arrays or collections. Otherwise just a new dictionary
220 * referring to the same objects is returned.
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000221 *
Felix Meschbergera0903df2009-01-19 10:40:28 +0000222 * @param deepCopy
223 * <code>true</code> if a deep copy is to be returned.
224 * @return
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000225 */
Felix Meschbergera0903df2009-01-19 10:40:28 +0000226 public Dictionary getProperties( boolean deepCopy )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000227 {
228 // no properties yet
Carsten Ziegelereb80d512007-08-15 11:17:41 +0000229 if ( properties == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000230 {
231 return null;
232 }
233
Felix Meschbergera0903df2009-01-19 10:40:28 +0000234 CaseInsensitiveDictionary props = new CaseInsensitiveDictionary( properties, deepCopy );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000235
236 // fix special properties (pid, factory PID, bundle location)
Carsten Ziegelereb80d512007-08-15 11:17:41 +0000237 setAutoProperties( props, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000238
239 return props;
240 }
241
242
243 /* (non-Javadoc)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000244 * @see org.osgi.service.cm.Configuration#update()
245 */
246 public void update() throws IOException
247 {
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000248 PersistenceManager localPersistenceManager = getPersistenceManager();
249 if ( localPersistenceManager != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000250 {
251 // read configuration from persistence (again)
Felix Meschbergeref470042009-08-19 05:52:41 +0000252 Dictionary properties = localPersistenceManager.load( getPid() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000253
254 // ensure serviceReference pid
255 String servicePid = ( String ) properties.get( Constants.SERVICE_PID );
Felix Meschbergeref470042009-08-19 05:52:41 +0000256 if ( servicePid != null && !getPid().equals( servicePid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000257 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000258 throw new IOException( "PID of configuration file does match requested PID; expected " + getPid() + ", got "
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000259 + servicePid );
260 }
261
Felix Meschberger2941ef92007-08-20 13:15:16 +0000262 configureFromPersistence( properties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000263
Felix Meschberger02f457d2009-08-20 06:27:17 +0000264 // update the service but do not fire an CM_UPDATED event
265 getConfigurationManager().updated( this, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000266 }
267 }
268
269
270 /* (non-Javadoc)
271 * @see org.osgi.service.cm.Configuration#update(java.util.Dictionary)
272 */
273 public void update( Dictionary properties ) throws IOException
274 {
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000275 PersistenceManager localPersistenceManager = getPersistenceManager();
276 if ( localPersistenceManager != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000277 {
278 CaseInsensitiveDictionary newProperties = new CaseInsensitiveDictionary( properties );
279
Felix Meschbergeref470042009-08-19 05:52:41 +0000280 setAutoProperties( newProperties, true );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000281
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000282 // persist new configuration
Felix Meschbergeref470042009-08-19 05:52:41 +0000283 localPersistenceManager.store( getPid(), newProperties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000284
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000285 // if this is a factory configuration, update the factory with
286 String factoryPid = getFactoryPid();
287 if ( factoryPid != null )
288 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000289 // If this is a new factory configuration, we also have to add
290 // it to the configuration manager cache
291 if ( isNew() )
292 {
293 getConfigurationManager().cacheConfiguration( this );
294 }
295
296 Factory factory = getConfigurationManager().getFactory( factoryPid );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000297 if ( factory.addPID( getPid() ) )
298 {
299 // only write back if the pid was not already registered
300 // with the factory
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000301 try
302 {
303 factory.store();
304 }
305 catch ( IOException ioe )
306 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000307 getConfigurationManager().log( LogService.LOG_ERROR,
308 "Failure storing factory " + factoryPid + " with new configuration " + getPid(), ioe );
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000309 }
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000310 }
311 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000312
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000313 // finally assign the configuration for use
314 configure( newProperties );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000315
Felix Meschberger02f457d2009-08-20 06:27:17 +0000316 // update the service and fire an CM_UPDATED event
317 getConfigurationManager().updated( this, true );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000318 }
319 }
320
321
322 //---------- Object overwrites --------------------------------------------
323
324 public boolean equals( Object obj )
325 {
326 if ( obj == this )
327 {
328 return true;
329 }
330
331 if ( obj instanceof Configuration )
332 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000333 return getPid().equals( ( ( Configuration ) obj ).getPid() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000334 }
335
336 return false;
337 }
338
339
340 public int hashCode()
341 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000342 return getPid().hashCode();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000343 }
344
345
346 public String toString()
347 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000348 return "Configuration PID=" + getPid() + ", factoryPID=" + factoryPID + ", bundleLocation=" + getBundleLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000349 }
350
351
Felix Meschbergeref470042009-08-19 05:52:41 +0000352 // ---------- private helper -----------------------------------------------
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000353
354 void store() throws IOException
355 {
Felix Meschbergera0903df2009-01-19 10:40:28 +0000356 // we don't need a deep copy, since we are not modifying
357 // any value in the dictionary itself. we are just adding
358 // properties to it, which are required for storing
359 Dictionary props = getProperties( false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000360
361 // if this is a new configuration, we just use an empty Dictionary
362 if ( props == null )
363 {
364 props = new Hashtable();
365
Felix Meschberger6a698df2009-08-16 18:38:46 +0000366 // add automatic properties including the bundle location (if
367 // statically bound)
Felix Meschbergeref470042009-08-19 05:52:41 +0000368 setAutoProperties( props, true );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000369 }
Felix Meschbergeref470042009-08-19 05:52:41 +0000370 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000371 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000372 replaceProperty( props, ConfigurationAdmin.SERVICE_BUNDLELOCATION, getStaticBundleLocation() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000373 }
374
375 // only store now, if this is not a new configuration
Felix Meschbergeref470042009-08-19 05:52:41 +0000376 getPersistenceManager().store( getPid(), props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000377 }
378
379
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000380 /**
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000381 * Returns the time of the last update of this configuration object. In
382 * particular this is the time at which the properties field has been
383 * set to new values.
384 * <p>
385 * This value may be compared to the {@link #getLastUpdatedTime()} to
386 * decide whether to update the ManagedService[Factory] or not.
387 */
388 long getLastModificationTime()
389 {
390 return lastModificationTime;
391 }
392
393 /**
394 * Returns the time of the last update of this configuration to the
395 * subscribing ManagedService or ManagedServiceFactory. This time may be
396 * compared to the {@link #getLastModificationTime()} to decide whether
397 * the configuration should be updated or not.
398 */
399 long getLastUpdatedTime()
400 {
401 return lastUpdatedTime;
402 }
403
404 /**
405 * Sets the time of the last update of this configuration to the
406 * ManagedService or ManagedServiceFactory subscribed to this configuration.
407 * <p>
408 * This method should only be called from the Update Thread after supplying
409 * the configuration to the ManagedService[Factory].
410 */
411 void setLastUpdatedTime( )
412 {
413 this.lastUpdatedTime = System.currentTimeMillis();
414 }
415
416 /**
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000417 * Returns <code>false</code> if this configuration contains configuration
418 * properties. Otherwise <code>true</code> is returned and this is a
419 * newly creted configuration object whose {@link #update(Dictionary)}
420 * method has never been called.
421 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000422 boolean isNew()
423 {
424 return properties == null;
425 }
426
427
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000428 /**
429 * Returns <code>true</code> if this configuration has already been deleted
430 * on the persistence.
431 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000432 boolean isDeleted()
433 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000434 return isDeleted;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000435 }
436
437
Felix Meschberger2941ef92007-08-20 13:15:16 +0000438 private void configureFromPersistence( Dictionary properties )
439 {
440 // if the this is not an empty/new configuration, accept the properties
441 // otherwise just set the properties field to null
442 if ( properties.get( CONFIGURATION_NEW ) == null )
443 {
444 configure( properties );
445 }
446 else
447 {
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000448 configure( null );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000449 }
450 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000451
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000452 private void configure( final Dictionary properties )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000453 {
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000454 final CaseInsensitiveDictionary newProperties;
455 if ( properties == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000456 {
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000457 newProperties = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000458 }
459 else
460 {
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000461 // remove predefined properties
462 clearAutoProperties( properties );
463
464 // ensure CaseInsensitiveDictionary
465 if ( properties instanceof CaseInsensitiveDictionary )
466 {
467 newProperties = ( CaseInsensitiveDictionary ) properties;
468 }
469 else
470 {
471 newProperties = new CaseInsensitiveDictionary( properties );
472 }
473 }
474
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000475 synchronized ( this )
476 {
477 this.properties = newProperties;
478 this.lastModificationTime = System.currentTimeMillis();
479 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000480 }
481
482
483 void setAutoProperties( Dictionary properties, boolean withBundleLocation )
484 {
485 // set pid and factory pid in the properties
Felix Meschbergeref470042009-08-19 05:52:41 +0000486 replaceProperty( properties, Constants.SERVICE_PID, getPid() );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000487 replaceProperty( properties, ConfigurationAdmin.SERVICE_FACTORYPID, factoryPID );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000488
489 // bundle location is not set here
490 if ( withBundleLocation )
491 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000492 replaceProperty( properties, ConfigurationAdmin.SERVICE_BUNDLELOCATION, getStaticBundleLocation() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000493 }
494 else
495 {
496 properties.remove( ConfigurationAdmin.SERVICE_BUNDLELOCATION );
497 }
498 }
499
500
Felix Meschbergeref470042009-08-19 05:52:41 +0000501 static void clearAutoProperties( Dictionary properties )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000502 {
503 properties.remove( Constants.SERVICE_PID );
504 properties.remove( ConfigurationAdmin.SERVICE_FACTORYPID );
505 properties.remove( ConfigurationAdmin.SERVICE_BUNDLELOCATION );
506 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000507}