blob: d7060fb973d0d5252e9ff8fa73e45076c7db9e2c [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.
Felix Meschbergerf23eb072009-08-31 14:04:33 +000086 *
87 * FELIX-1545 provides further update to the concurrency situation defining
88 * three more failure cases:
89 *
90 * (1) System.currentTimeMillis() may be too coarse graind to protect
91 * against race condition.
92 * (2) ManagedService update sets last update time regardless of whether
93 * configuration was provided or not. This may cause a configuration
94 * update to be lost.
95 * (3) ManagedService update does not respect last update time which
96 * in turn may cause duplicate configuration delivery.
Felix Meschbergerfd52e312009-08-29 19:44:58 +000097 */
98
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +000099 /**
Felix Meschberger2941ef92007-08-20 13:15:16 +0000100 * The name of a synthetic property stored in the persisted configuration
101 * data to indicate that the configuration data is new, that is created but
102 * never updated (value is "_felix_.cm.newConfiguration").
103 * <p>
104 * This special property is stored by the
105 * {@link #ConfigurationImpl(ConfigurationManager, PersistenceManager, String, String, String)}
106 * constructor, when the configuration is first created and persisted and is
107 * interpreted by the
108 * {@link #ConfigurationImpl(ConfigurationManager, PersistenceManager, Dictionary)}
109 * method when the configuration data is loaded in a new object.
110 * <p>
111 * The goal of this property is to keep the information on whether
112 * configuration data is new (but persisted as per the spec) or has already
113 * been assigned with possible no data.
114 */
115 private static final String CONFIGURATION_NEW = "_felix_.cm.newConfiguration";
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000116
Felix Meschberger2941ef92007-08-20 13:15:16 +0000117 /**
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000118 * The factory serviceReference PID of this configuration or <code>null</code> if this
119 * is not a factory configuration.
120 */
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000121 private final String factoryPID;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000122
123 /**
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000124 * The configuration data of this configuration instance. This is a private
125 * copy of the properties of which a copy is made when the
Felix Meschbergeref470042009-08-19 05:52:41 +0000126 * {@link #getProperties()} method is called. This field is
127 * <code>null</code> if the configuration has been created and never been
128 * updated with acutal configuration properties.
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000129 */
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000130 private volatile CaseInsensitiveDictionary properties;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000131
Felix Meschbergerf4631322008-03-10 12:32:35 +0000132 /**
Felix Meschbergeref470042009-08-19 05:52:41 +0000133 * Flag indicating that this configuration has been deleted.
134 *
135 * @see #isDeleted()
Felix Meschbergerf4631322008-03-10 12:32:35 +0000136 */
Felix Meschbergeref470042009-08-19 05:52:41 +0000137 private volatile boolean isDeleted;
138
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000139 /**
Felix Meschbergerf23eb072009-08-31 14:04:33 +0000140 * Current configuration modification counter. This field is incremented
141 * each time the {@link #properties} field is set (in the constructor or the
142 * {@link #configure(Dictionary)} method. field.
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000143 */
144 private volatile long lastModificationTime;
145
146 /**
Felix Meschbergerf23eb072009-08-31 14:04:33 +0000147 * Value of the {@link #lastModificationTime} counter at the time the non-
148 * <code>null</code> properties of this configuration have been updated to a
149 * ManagedService[Factory]. This field is initialized to -1 in the
150 * constructors and set to the value of the {@link #lastModificationTime} by
151 * the {@link #setLastUpdatedTime()} method called from the respective task
152 * updating the configuration.
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000153 *
154 * @see #lastModificationTime
155 */
156 private volatile long lastUpdatedTime;
157
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000158
159 ConfigurationImpl( ConfigurationManager configurationManager, PersistenceManager persistenceManager,
160 Dictionary properties )
161 {
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000162 super( configurationManager, persistenceManager, ( String ) properties.remove( Constants.SERVICE_PID ),
163 ( String ) properties.remove( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000164
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000165 this.factoryPID = ( String ) properties.remove( ConfigurationAdmin.SERVICE_FACTORYPID );
Felix Meschbergeref470042009-08-19 05:52:41 +0000166 this.isDeleted = false;
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000167 this.lastUpdatedTime = -1;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000168
Felix Meschberger2941ef92007-08-20 13:15:16 +0000169 // set the properties internally
170 configureFromPersistence( properties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000171 }
172
173
174 ConfigurationImpl( ConfigurationManager configurationManager, PersistenceManager persistenceManager, String pid,
Felix Meschberger2941ef92007-08-20 13:15:16 +0000175 String factoryPid, String bundleLocation ) throws IOException
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000176 {
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000177 super( configurationManager, persistenceManager, pid, bundleLocation );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000178
Felix Meschberger2941ef92007-08-20 13:15:16 +0000179 this.factoryPID = factoryPid;
Felix Meschbergeref470042009-08-19 05:52:41 +0000180 this.isDeleted = false;
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000181 this.lastUpdatedTime = -1;
Felix Meschberger2941ef92007-08-20 13:15:16 +0000182
Felix Meschbergerf23eb072009-08-31 14:04:33 +0000183 // first "update"
184 this.properties = null;
185 setLastModificationTime();
186
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000187 // this is a new configuration object, store immediately unless
188 // the new configuration object is created from a factory, in which
189 // case the configuration is only stored when first updated
Felix Meschbergeref470042009-08-19 05:52:41 +0000190 if ( factoryPid == null )
191 {
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000192 Dictionary props = new Hashtable();
Felix Meschbergeref470042009-08-19 05:52:41 +0000193 setAutoProperties( props, true );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000194 props.put( CONFIGURATION_NEW, Boolean.TRUE );
195 persistenceManager.store( pid, props );
196 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000197 }
198
199
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000200 public void delete() throws IOException
201 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000202 this.isDeleted = true;
203 getPersistenceManager().delete( this.getPid() );
Felix Meschbergercefe5eb2009-08-19 12:37:32 +0000204 getConfigurationManager().setDynamicBundleLocation( this.getPid(), null );
205 getConfigurationManager().deleted( this );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000206 }
207
208
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000209 public String getPid()
210 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000211 return getBaseId();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000212 }
213
214
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000215 public String getFactoryPid()
216 {
Carsten Ziegelereb80d512007-08-15 11:17:41 +0000217 return factoryPID;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000218 }
219
220
Felix Meschbergera0903df2009-01-19 10:40:28 +0000221 /**
222 * Returns an optionally deep copy of the properties of this configuration
223 * instance.
224 * <p>
225 * This method returns a copy of the internal dictionary. If the
226 * <code>deepCopy</code> parameter is true array and collection values are
227 * copied into new arrays or collections. Otherwise just a new dictionary
228 * referring to the same objects is returned.
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000229 *
Felix Meschbergera0903df2009-01-19 10:40:28 +0000230 * @param deepCopy
231 * <code>true</code> if a deep copy is to be returned.
232 * @return
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000233 */
Felix Meschbergera0903df2009-01-19 10:40:28 +0000234 public Dictionary getProperties( boolean deepCopy )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000235 {
236 // no properties yet
Carsten Ziegelereb80d512007-08-15 11:17:41 +0000237 if ( properties == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000238 {
239 return null;
240 }
241
Felix Meschbergera0903df2009-01-19 10:40:28 +0000242 CaseInsensitiveDictionary props = new CaseInsensitiveDictionary( properties, deepCopy );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000243
244 // fix special properties (pid, factory PID, bundle location)
Carsten Ziegelereb80d512007-08-15 11:17:41 +0000245 setAutoProperties( props, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000246
247 return props;
248 }
249
250
251 /* (non-Javadoc)
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000252 * @see org.osgi.service.cm.Configuration#update()
253 */
254 public void update() throws IOException
255 {
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000256 PersistenceManager localPersistenceManager = getPersistenceManager();
257 if ( localPersistenceManager != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000258 {
259 // read configuration from persistence (again)
Felix Meschbergeref470042009-08-19 05:52:41 +0000260 Dictionary properties = localPersistenceManager.load( getPid() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000261
262 // ensure serviceReference pid
263 String servicePid = ( String ) properties.get( Constants.SERVICE_PID );
Felix Meschbergeref470042009-08-19 05:52:41 +0000264 if ( servicePid != null && !getPid().equals( servicePid ) )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000265 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000266 throw new IOException( "PID of configuration file does match requested PID; expected " + getPid() + ", got "
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000267 + servicePid );
268 }
269
Felix Meschberger2941ef92007-08-20 13:15:16 +0000270 configureFromPersistence( properties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000271
Felix Meschberger02f457d2009-08-20 06:27:17 +0000272 // update the service but do not fire an CM_UPDATED event
273 getConfigurationManager().updated( this, false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000274 }
275 }
276
277
278 /* (non-Javadoc)
279 * @see org.osgi.service.cm.Configuration#update(java.util.Dictionary)
280 */
281 public void update( Dictionary properties ) throws IOException
282 {
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000283 PersistenceManager localPersistenceManager = getPersistenceManager();
284 if ( localPersistenceManager != null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000285 {
286 CaseInsensitiveDictionary newProperties = new CaseInsensitiveDictionary( properties );
287
Felix Meschbergeref470042009-08-19 05:52:41 +0000288 setAutoProperties( newProperties, true );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000289
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000290 // persist new configuration
Felix Meschbergeref470042009-08-19 05:52:41 +0000291 localPersistenceManager.store( getPid(), newProperties );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000292
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000293 // if this is a factory configuration, update the factory with
294 String factoryPid = getFactoryPid();
295 if ( factoryPid != null )
296 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000297 // If this is a new factory configuration, we also have to add
298 // it to the configuration manager cache
299 if ( isNew() )
300 {
301 getConfigurationManager().cacheConfiguration( this );
302 }
303
304 Factory factory = getConfigurationManager().getFactory( factoryPid );
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000305 if ( factory.addPID( getPid() ) )
306 {
307 // only write back if the pid was not already registered
308 // with the factory
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000309 try
310 {
311 factory.store();
312 }
313 catch ( IOException ioe )
314 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000315 getConfigurationManager().log( LogService.LOG_ERROR,
316 "Failure storing factory " + factoryPid + " with new configuration " + getPid(), ioe );
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000317 }
Felix Meschbergerfbc7dc12008-08-06 08:25:58 +0000318 }
319 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000320
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000321 // finally assign the configuration for use
322 configure( newProperties );
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000323
Felix Meschberger02f457d2009-08-20 06:27:17 +0000324 // update the service and fire an CM_UPDATED event
325 getConfigurationManager().updated( this, true );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000326 }
327 }
328
329
330 //---------- Object overwrites --------------------------------------------
331
332 public boolean equals( Object obj )
333 {
334 if ( obj == this )
335 {
336 return true;
337 }
338
339 if ( obj instanceof Configuration )
340 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000341 return getPid().equals( ( ( Configuration ) obj ).getPid() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000342 }
343
344 return false;
345 }
346
347
348 public int hashCode()
349 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000350 return getPid().hashCode();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000351 }
352
353
354 public String toString()
355 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000356 return "Configuration PID=" + getPid() + ", factoryPID=" + factoryPID + ", bundleLocation=" + getBundleLocation();
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000357 }
358
359
Felix Meschbergeref470042009-08-19 05:52:41 +0000360 // ---------- private helper -----------------------------------------------
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000361
362 void store() throws IOException
363 {
Felix Meschbergera0903df2009-01-19 10:40:28 +0000364 // we don't need a deep copy, since we are not modifying
365 // any value in the dictionary itself. we are just adding
366 // properties to it, which are required for storing
367 Dictionary props = getProperties( false );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000368
369 // if this is a new configuration, we just use an empty Dictionary
370 if ( props == null )
371 {
372 props = new Hashtable();
373
Felix Meschberger6a698df2009-08-16 18:38:46 +0000374 // add automatic properties including the bundle location (if
375 // statically bound)
Felix Meschbergeref470042009-08-19 05:52:41 +0000376 setAutoProperties( props, true );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000377 }
Felix Meschbergeref470042009-08-19 05:52:41 +0000378 else
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000379 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000380 replaceProperty( props, ConfigurationAdmin.SERVICE_BUNDLELOCATION, getStaticBundleLocation() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000381 }
382
383 // only store now, if this is not a new configuration
Felix Meschbergeref470042009-08-19 05:52:41 +0000384 getPersistenceManager().store( getPid(), props );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000385 }
386
387
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000388 /**
Felix Meschbergerf23eb072009-08-31 14:04:33 +0000389 * Increments the last modification counter of this configuration to cause
390 * the ManagedService or ManagedServiceFactory subscribed to this
391 * configuration to be updated.
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000392 * <p>
Felix Meschbergerf23eb072009-08-31 14:04:33 +0000393 * This method is intended to only be called by the constructor(s) of this
394 * class and the {@link #update(Dictionary)} method to indicate to the
395 * update threads, the configuration is ready for distribution.
396 * <p>
397 * Setting the properties field and incrementing this counter should be
398 * done synchronized on this instance.
399 */
400 void setLastModificationTime( )
401 {
402 this.lastModificationTime++;
403 }
404
405
406 /**
407 * Returns the modification counter of the last modification of the
408 * properties of this configuration object.
409 * <p>
410 * This value may be compared to the {@link #getLastUpdatedTime()} to decide
411 * whether to update the ManagedService[Factory] or not.
412 * <p>
413 * Getting the properties of this configuration and this counter should be
414 * done synchronized on this instance.
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000415 */
416 long getLastModificationTime()
417 {
418 return lastModificationTime;
419 }
420
Felix Meschbergerf23eb072009-08-31 14:04:33 +0000421
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000422 /**
Felix Meschbergerf23eb072009-08-31 14:04:33 +0000423 * Returns the modification counter of the last update of this configuration
424 * to the subscribing ManagedService or ManagedServiceFactory. This value
425 * may be compared to the {@link #getLastModificationTime()} to decide
426 * whether the configuration should be updated or not.
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000427 */
428 long getLastUpdatedTime()
429 {
430 return lastUpdatedTime;
431 }
432
Felix Meschbergerf23eb072009-08-31 14:04:33 +0000433
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000434 /**
Felix Meschberger8d9851a2010-08-25 13:22:44 +0000435 * Sets the last update time field to the given value of the last
436 * modification time to indicate the version of configuration properties
437 * that have been updated in a ManagedService[Factory].
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000438 * <p>
439 * This method should only be called from the Update Thread after supplying
440 * the configuration to the ManagedService[Factory].
Felix Meschberger8d9851a2010-08-25 13:22:44 +0000441 *
442 * @param lastModificationTime The value of the
443 * {@link #getLastModificationTime() last modification time field} at
444 * which the properties have been extracted from the configuration to
445 * be supplied to the service.
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000446 */
Felix Meschberger8d9851a2010-08-25 13:22:44 +0000447 void setLastUpdatedTime( long lastModificationTime )
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000448 {
Felix Meschberger8d9851a2010-08-25 13:22:44 +0000449 synchronized ( this )
450 {
451 this.lastUpdatedTime = lastModificationTime;
Felix Meschbergerf23eb072009-08-31 14:04:33 +0000452 }
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000453 }
454
Felix Meschberger8d9851a2010-08-25 13:22:44 +0000455
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000456 /**
Felix Meschberger0c4e7042008-08-06 07:41:48 +0000457 * Returns <code>false</code> if this configuration contains configuration
458 * properties. Otherwise <code>true</code> is returned and this is a
459 * newly creted configuration object whose {@link #update(Dictionary)}
460 * method has never been called.
461 */
Felix Meschberger2941ef92007-08-20 13:15:16 +0000462 boolean isNew()
463 {
464 return properties == null;
465 }
466
467
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000468 /**
469 * Returns <code>true</code> if this configuration has already been deleted
470 * on the persistence.
471 */
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000472 boolean isDeleted()
473 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000474 return isDeleted;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000475 }
476
477
Felix Meschberger2941ef92007-08-20 13:15:16 +0000478 private void configureFromPersistence( Dictionary properties )
479 {
480 // if the this is not an empty/new configuration, accept the properties
481 // otherwise just set the properties field to null
482 if ( properties.get( CONFIGURATION_NEW ) == null )
483 {
484 configure( properties );
485 }
486 else
487 {
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000488 configure( null );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000489 }
490 }
Felix Meschbergerdf26ae82009-08-14 19:50:43 +0000491
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000492 private void configure( final Dictionary properties )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000493 {
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000494 final CaseInsensitiveDictionary newProperties;
495 if ( properties == null )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000496 {
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000497 newProperties = null;
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000498 }
499 else
500 {
Felix Meschbergera0e8e332009-08-18 07:52:51 +0000501 // remove predefined properties
502 clearAutoProperties( properties );
503
504 // ensure CaseInsensitiveDictionary
505 if ( properties instanceof CaseInsensitiveDictionary )
506 {
507 newProperties = ( CaseInsensitiveDictionary ) properties;
508 }
509 else
510 {
511 newProperties = new CaseInsensitiveDictionary( properties );
512 }
513 }
514
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000515 synchronized ( this )
516 {
517 this.properties = newProperties;
Felix Meschbergerf23eb072009-08-31 14:04:33 +0000518 setLastModificationTime();
Felix Meschbergerfd52e312009-08-29 19:44:58 +0000519 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000520 }
521
522
523 void setAutoProperties( Dictionary properties, boolean withBundleLocation )
524 {
525 // set pid and factory pid in the properties
Felix Meschbergeref470042009-08-19 05:52:41 +0000526 replaceProperty( properties, Constants.SERVICE_PID, getPid() );
Felix Meschberger2941ef92007-08-20 13:15:16 +0000527 replaceProperty( properties, ConfigurationAdmin.SERVICE_FACTORYPID, factoryPID );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000528
529 // bundle location is not set here
530 if ( withBundleLocation )
531 {
Felix Meschbergeref470042009-08-19 05:52:41 +0000532 replaceProperty( properties, ConfigurationAdmin.SERVICE_BUNDLELOCATION, getStaticBundleLocation() );
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000533 }
534 else
535 {
536 properties.remove( ConfigurationAdmin.SERVICE_BUNDLELOCATION );
537 }
538 }
539
540
Felix Meschbergeref470042009-08-19 05:52:41 +0000541 static void clearAutoProperties( Dictionary properties )
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000542 {
543 properties.remove( Constants.SERVICE_PID );
544 properties.remove( ConfigurationAdmin.SERVICE_FACTORYPID );
545 properties.remove( ConfigurationAdmin.SERVICE_BUNDLELOCATION );
546 }
Felix Meschbergeradd2b4a2007-04-11 18:12:33 +0000547}