KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > store > access > PropertyConglomerate


1 /*
2
3    Derby - Class org.apache.derby.impl.store.access.PropertyConglomerate
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.store.access;
23
24 import org.apache.derby.iapi.reference.Attribute;
25 import org.apache.derby.iapi.reference.Property;
26 import org.apache.derby.iapi.reference.SQLState;
27
28 import org.apache.derby.iapi.types.UserType;
29 import org.apache.derby.impl.store.access.UTF;
30 import org.apache.derby.impl.store.access.UTFQualifier;
31 import org.apache.derby.iapi.services.io.FormatableBitSet;
32 import org.apache.derby.iapi.services.io.FormatableHashtable;
33 import org.apache.derby.iapi.services.locks.ShExLockable;
34 import org.apache.derby.iapi.services.locks.ShExQual;
35 import org.apache.derby.iapi.services.daemon.Serviceable;
36 import org.apache.derby.iapi.services.locks.C_LockFactory;
37 import org.apache.derby.iapi.services.locks.Latch;
38 import org.apache.derby.iapi.services.locks.LockFactory;
39 import org.apache.derby.iapi.services.property.PropertyUtil;
40
41 import org.apache.derby.iapi.services.monitor.Monitor;
42 import org.apache.derby.iapi.services.sanity.SanityManager;
43 import org.apache.derby.iapi.services.io.Formatable;
44 import org.apache.derby.iapi.error.StandardException;
45 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
46 import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
47 import org.apache.derby.iapi.store.access.AccessFactory;
48 import org.apache.derby.iapi.store.access.AccessFactoryGlobals;
49 import org.apache.derby.iapi.store.access.ConglomerateController;
50 import org.apache.derby.iapi.services.property.PropertyFactory;
51 import org.apache.derby.iapi.services.property.PropertySetCallback;
52 import org.apache.derby.iapi.store.access.Qualifier;
53 import org.apache.derby.iapi.store.access.ScanController;
54 import org.apache.derby.iapi.store.access.TransactionController;
55 import org.apache.derby.iapi.store.raw.RawStoreFactory;
56 import org.apache.derby.iapi.types.DataValueDescriptor;
57
58 import java.io.Serializable JavaDoc;
59 import java.util.Dictionary JavaDoc;
60 import java.util.Enumeration JavaDoc;
61 import java.util.Hashtable JavaDoc;
62 import java.util.Properties JavaDoc;
63
64 /**
65 Stores properties in a congolmerate with complete transactional support.
66 <p>
67 The PropertyConglomerate contains one row with 2 columns per property.
68 Column 0 is the UTF key, and column 1 is the data.
69 <p>
70
71 <p>
72 The property conglomerate manages the storage of database properties
73 and thier defaults. Each property is stored as a row in the
74 PropertyConglomerate
75 <OL>
76 <LI>Column 0 is the UTF key,
77 <LI>Column 1 is the data.
78 </OL>
79 All the property defaults are stored in a single row of the Property
80 Conglomerate:
81 <OL>
82 <LI>Column 0 is the UTF key "derby.defaultPropertyName".
83 <LI>Column 1 is a FormatableProperties object with one
84     row per default property.
85 </OL>
86 <p>
87 In general a propery default defines it value if the property
88 itself is not defined.
89
90 <p>
91 Because the properties conglomerate is stored in a conglomerate
92 the information it contains is not available before the raw store
93 runs recovery. To make a small number of properties (listed in
94 servicePropertyList) available during early boot, this copies
95 them to services.properties.
96 **/

97 class PropertyConglomerate
98 {
99     protected long propertiesConglomId;
100     protected Properties JavaDoc serviceProperties;
101     private LockFactory lf;
102     private Dictionary cachedSet;
103     private CacheLock cachedLock;
104
105     private PropertyFactory pf;
106
107     /* Constructors for This class: */
108
109     PropertyConglomerate(
110     TransactionController tc,
111     boolean create,
112     Properties JavaDoc serviceProperties,
113     PropertyFactory pf)
114         throws StandardException
115     {
116         this.pf = pf;
117
118         if (!create) {
119             String JavaDoc id = serviceProperties.getProperty(Property.PROPERTIES_CONGLOM_ID);
120             if (id == null) {
121                 create = true;
122             } else {
123                 try {
124                     propertiesConglomId = Long.valueOf(id).longValue();
125                 } catch (NumberFormatException JavaDoc nfe) {
126                     throw Monitor.exceptionStartingModule(nfe) ;
127                 }
128             }
129         }
130
131         if (create) {
132             DataValueDescriptor[] template = makeNewTemplate();
133
134             Properties JavaDoc conglomProperties = new Properties JavaDoc();
135
136             conglomProperties.put(
137                 Property.PAGE_SIZE_PARAMETER,
138                 RawStoreFactory.PAGE_SIZE_STRING);
139
140             conglomProperties.put(
141                 RawStoreFactory.PAGE_RESERVED_SPACE_PARAMETER,
142                 RawStoreFactory.PAGE_RESERVED_ZERO_SPACE_STRING);
143
144             propertiesConglomId =
145                 tc.createConglomerate(
146                     AccessFactoryGlobals.HEAP,
147                     template,
148                     null,
149                     conglomProperties,
150                     TransactionController.IS_DEFAULT);
151
152             serviceProperties.put(
153                 Property.PROPERTIES_CONGLOM_ID,
154                 Long.toString(propertiesConglomId));
155         }
156
157         this.serviceProperties = serviceProperties;
158
159         lf = ((RAMTransaction) tc).getAccessManager().getLockFactory();
160         cachedLock = new CacheLock(this);
161
162         PC_XenaVersion softwareVersion = new PC_XenaVersion();
163         if (create)
164             setProperty(tc,DataDictionary.PROPERTY_CONGLOMERATE_VERSION,
165                          softwareVersion, true);
166         else
167             softwareVersion.upgradeIfNeeded(tc,this,serviceProperties);
168
169         getCachedDbProperties(tc);
170     }
171
172     /* Private/Protected methods of This class: */
173
174     /**
175      * Create a new PropertyConglomerate row, with values in it.
176      **/

177     private DataValueDescriptor[] makeNewTemplate(String JavaDoc key, Serializable JavaDoc value)
178     {
179         DataValueDescriptor[] template = new DataValueDescriptor[2];
180
181         template[0] = new UTF(key);
182         template[1] = new UserType(value);
183
184         return(template);
185     }
186
187     /**
188      * Create a new empty PropertyConglomerate row, to fetch values into.
189      **/

190     private DataValueDescriptor[] makeNewTemplate()
191     {
192         DataValueDescriptor[] template = new DataValueDescriptor[2];
193
194         template[0] = new UTF();
195         template[1] = new UserType();
196
197         return(template);
198     }
199
200     /**
201      * Open a scan on the properties conglomerate looking for "key".
202      * <p>
203      * Open a scan on the properties conglomerate qualified to
204      * find the row with value key in column 0. Both column 0
205      * and column 1 are included in the scan list.
206      *
207      * @return an open ScanController on the PropertyConglomerate.
208      *
209      * @param tc The transaction to do the Conglomerate work under.
210      * @param key The "key" of the property that is being requested.
211      * @param open_mode Whether we are setting or getting the property.
212      *
213      * @exception StandardException Standard exception policy.
214      **/

215     private ScanController openScan(
216     TransactionController tc,
217     String JavaDoc key,
218     int open_mode)
219         throws StandardException
220     {
221         Qualifier[][] qualifiers = null;
222
223         if (key != null) {
224             // Set up qualifier to look for the row with key value in column[0]
225
qualifiers = new Qualifier[1][];
226             qualifiers[0] = new Qualifier[1];
227             qualifiers[0][0] = new UTFQualifier(0, key);
228         }
229
230         // open the scan, clients will do the fetches and close.
231
ScanController scan =
232             tc.openScan(
233                 propertiesConglomId,
234                 false, // don't hold over the commit
235
open_mode,
236                 TransactionController.MODE_TABLE,
237                 TransactionController.ISOLATION_SERIALIZABLE,
238                 (FormatableBitSet) null,
239                 (DataValueDescriptor[]) null, // start key
240
ScanController.NA,
241                 qualifiers,
242                 (DataValueDescriptor[]) null, // stop key
243
ScanController.NA);
244
245         return(scan);
246     }
247     /* Package Methods of This class: */
248
249     /**
250         Set a property in the conglomerate.
251
252      @param key The key used to lookup this property.
253      @param value The value to be associated with this key. If null, delete the
254                         property from the properties list.
255     */

256
257     /**
258      * Set the default for a property.
259      * @exception StandardException Standard exception policy.
260      */

261     void setPropertyDefault(TransactionController tc, String JavaDoc key, Serializable JavaDoc value)
262          throws StandardException
263     {
264         lockProperties(tc);
265         Serializable JavaDoc valueToSave = null;
266         //
267
//If the default is visible we validate apply and map.
268
//otherwise we just map.
269
if (propertyDefaultIsVisible(tc,key))
270         {
271             valueToSave = validateApplyAndMap(tc,key,value,false);
272         }
273         else
274         {
275             synchronized (this) {
276                 Hashtable defaults = new Hashtable();
277                 getProperties(tc,defaults,false/*!stringsOnly*/,true/*defaultsOnly*/);
278                 validate(key,value,defaults);
279                 valueToSave = map(key,value,defaults);
280             }
281         }
282         savePropertyDefault(tc,key,valueToSave);
283     }
284
285     boolean propertyDefaultIsVisible(TransactionController tc,String JavaDoc key) throws StandardException
286     {
287         lockProperties(tc);
288         return(readProperty(tc,key) == null);
289     }
290     
291     void saveProperty(TransactionController tc, String JavaDoc key, Serializable JavaDoc value)
292          throws StandardException
293     {
294         if (saveServiceProperty(key,value)) return;
295
296         // Do a scan to see if the property already exists in the Conglomerate.
297
ScanController scan =
298             this.openScan(tc, key, TransactionController.OPENMODE_FORUPDATE);
299
300         DataValueDescriptor[] row = makeNewTemplate();
301
302         if (scan.fetchNext(row))
303         {
304             if (value == null)
305             {
306                 // A null input value means that we should delete the row
307

308                 scan.delete();
309             }
310             else
311             {
312                 // a value already exists, just replace the second columm
313

314                 row[1] = new UserType(value);
315
316                 scan.replace(row, (FormatableBitSet) null);
317             }
318
319             scan.close();
320         }
321         else
322         {
323             // The value does not exist in the Conglomerate.
324

325             scan.close();
326             scan = null;
327
328             if (value != null)
329             {
330                 // not a delete request, so insert the new property.
331

332                 row = makeNewTemplate(key, value);
333
334                 ConglomerateController cc =
335                     tc.openConglomerate(
336                         propertiesConglomId,
337                         false,
338                         TransactionController.OPENMODE_FORUPDATE,
339                         TransactionController.MODE_TABLE,
340                         TransactionController.ISOLATION_SERIALIZABLE);
341
342                 cc.insert(row);
343
344                 cc.close();
345             }
346         }
347     }
348
349     private boolean saveServiceProperty(String JavaDoc key, Serializable JavaDoc value)
350     {
351         if (PropertyUtil.isServiceProperty(key))
352         {
353             if (value != null)
354                 serviceProperties.put(key, value);
355             else
356                 serviceProperties.remove(key);
357             return true;
358         }
359         else
360         {
361             return false;
362         }
363     }
364
365     void savePropertyDefault(TransactionController tc, String JavaDoc key, Serializable JavaDoc value)
366          throws StandardException
367     {
368         if (saveServiceProperty(key,value)) return;
369
370         Dictionary defaults = (Dictionary)readProperty(tc,AccessFactoryGlobals.DEFAULT_PROPERTY_NAME);
371         if (defaults == null) defaults = new FormatableHashtable();
372         if (value==null)
373             defaults.remove(key);
374         else
375             defaults.put(key,value);
376         if (defaults.size() == 0) defaults = null;
377         saveProperty(tc,AccessFactoryGlobals.DEFAULT_PROPERTY_NAME,(Serializable JavaDoc)defaults);
378     }
379
380     private Serializable JavaDoc validateApplyAndMap(TransactionController tc,
381                                              String JavaDoc key, Serializable JavaDoc value, boolean dbOnlyProperty)
382          throws StandardException
383     {
384         Dictionary d = new Hashtable();
385         getProperties(tc,d,false/*!stringsOnly*/,false/*!defaultsOnly*/);
386         Serializable JavaDoc mappedValue = pf.doValidateApplyAndMap(tc, key,
387                                                                    value, d, dbOnlyProperty);
388         //
389
// RESOLVE: log device cannot be changed on the fly right now
390
if (key.equals(Attribute.LOG_DEVICE))
391         {
392             throw StandardException.newException(
393                     SQLState.RAWSTORE_CANNOT_CHANGE_LOGDEVICE);
394         }
395
396         if (mappedValue == null)
397             return value;
398         else
399             return mappedValue;
400     }
401
402     /**
403       Call the property set callbacks to map a proposed property value
404       to a value to save.
405       <P>
406       The caller must run this in a block synchronized on this
407       to serialize validations with changes to the set of
408       property callbacks
409       */

410     private Serializable JavaDoc map(String JavaDoc key,
411                              Serializable JavaDoc value,
412                              Dictionary set)
413          throws StandardException
414     {
415         return pf.doMap(key, value, set);
416     }
417
418     /**
419       Call the property set callbacks to validate a property change
420       against the property set provided.
421       <P>
422       The caller must run this in a block synchronized on this
423       to serialize validations with changes to the set of
424       property callbacks
425       */

426
427     private void validate(String JavaDoc key,
428                           Serializable JavaDoc value,
429                           Dictionary set)
430          throws StandardException
431     {
432         pf.validateSingleProperty(key, value, set);
433     }
434
435
436     private boolean bootPasswordChange(TransactionController tc,
437                                        String JavaDoc key,
438                                        Serializable JavaDoc value)
439          throws StandardException
440     {
441         // first check for boot password change - we don't put boot password
442
// in the servicePropertyList because if we do, then we expose the
443
// boot password in clear text
444
if (key.equals(Attribute.BOOT_PASSWORD))
445         {
446             // The user is trying to change the secret key.
447
// The secret key is never stored in clear text, but we
448
// store the encrypted form in the services.properties
449
// file. Swap the secret key with the encrypted form and
450
// put that in the services.properties file.
451
AccessFactory af = ((TransactionManager)tc).getAccessManager();
452
453             RawStoreFactory rsf = (RawStoreFactory)
454                 Monitor.findServiceModule(af, RawStoreFactory.MODULE);
455
456             // remove secret key from properties list if possible
457
serviceProperties.remove(Attribute.BOOT_PASSWORD);
458
459             value = rsf.changeBootPassword(serviceProperties, value);
460             serviceProperties.put(RawStoreFactory.ENCRYPTED_KEY,value);
461             return true;
462         }
463         else
464         {
465             return false;
466         }
467     }
468
469     /**
470      * Sets the Serializable object associated with a property key.
471      * <p>
472      * This implementation turns the setProperty into an insert into the
473      * PropertyConglomerate conglomerate.
474      * <p>
475      * See the discussion of getProperty().
476      * <p>
477      * The value stored may be a Formatable object or a Serializable object
478      * whose class name starts with java.*. This stops arbitary objects being
479      * stored in the database by class name, which will cause problems in
480      * obfuscated/non-obfuscated systems.
481      *
482      * @param tc The transaction to do the Conglomerate work under.
483      * @param key The key used to lookup this property.
484      * @param value The value to be associated with this key. If null,
485      * delete the property from the properties list.
486      *
487      * @exception StandardException Standard exception policy.
488      **/

489     void setProperty(
490     TransactionController tc,
491     String JavaDoc key,
492     Serializable JavaDoc value, boolean dbOnlyProperty)
493         throws StandardException
494     {
495         if (SanityManager.DEBUG)
496         {
497
498             if (!((value == null) || (value instanceof Formatable)))
499             {
500                 if (!(value.getClass().getName().startsWith("java.")))
501                 {
502                     SanityManager.THROWASSERT(
503                         "Non-formattable, non-java class - " +
504                         value.getClass().getName());
505                 }
506             }
507         }
508
509         lockProperties(tc);
510         Serializable JavaDoc valueToValidateAndApply = value;
511         //
512
//If we remove a property we validate and apply its default.
513
if (value == null)
514             valueToValidateAndApply = getPropertyDefault(tc,key);
515         Serializable JavaDoc valueToSave =
516             validateApplyAndMap(tc,key,valueToValidateAndApply, dbOnlyProperty);
517
518         //
519
//if this is a bootPasswordChange we save it in
520
//a special way.
521
if (bootPasswordChange(tc,key,value))
522             return;
523
524         //
525
//value==null means we are removing a property.
526
//To remove the property we call saveProperty with
527
//a null value. Note we avoid saving the mapped
528
//DEFAULT value returned by validateAndApply.
529
else if (value==null)
530             saveProperty(tc,key,null);
531         //
532
//value != null means we simply save the possibly
533
//mapped value of the property returned by
534
//validateAndApply.
535
else
536             saveProperty(tc,key,valueToSave);
537     }
538
539     private Serializable JavaDoc readProperty(TransactionController tc,
540                                       String JavaDoc key) throws StandardException
541     {
542         // scan the table for a row with matching "key"
543
ScanController scan = openScan(tc, key, 0);
544
545         DataValueDescriptor[] row = makeNewTemplate();
546
547         // did we find at least one row?
548
boolean isThere = scan.fetchNext(row);
549         
550         scan.close();
551
552         if (!isThere) return null;
553
554         return (Serializable JavaDoc) (((UserType) row[1]).getObject());
555     }
556
557     private Serializable JavaDoc getCachedProperty(TransactionController tc,
558                                            String JavaDoc key) throws StandardException
559     {
560         //
561
//Get the cached set of properties.
562
Dictionary dbProps = getCachedDbProperties(tc);
563
564         //
565
//Return the value if it is defined.
566
if (dbProps.get(key) != null)
567             return (Serializable JavaDoc) dbProps.get(key);
568         else
569             return getCachedPropertyDefault(tc,key,dbProps);
570     }
571
572     private Serializable JavaDoc getCachedPropertyDefault(TransactionController tc,
573                                                   String JavaDoc key,
574                                                   Dictionary dbProps)
575          throws StandardException
576     {
577         //
578
//Get the cached set of properties.
579
if (dbProps == null) dbProps = getCachedDbProperties(tc);
580         //
581
//return the default for the value if it is defined.
582
Dictionary defaults = (Dictionary)dbProps.get(AccessFactoryGlobals.DEFAULT_PROPERTY_NAME);
583         if (defaults == null)
584             return null;
585         else
586             return (Serializable JavaDoc)defaults.get(key);
587     }
588
589     /**
590      * Gets the de-serialized object associated with a property key.
591      * <p>
592      * The Store provides a transaction protected list of database properties.
593      * Higher levels of the system can store and retrieve these properties
594      * once Recovery has finished. Each property is a serializable object
595      * and is stored/retrieved using a String key.
596      * <p>
597      * In this implementation a lookup is done on the PropertyConglomerate
598      * conglomerate, using a scan with "key" as the qualifier.
599      * <p>
600      * @param tc The transaction to do the Conglomerate work under.
601      * @param key The "key" of the property that is being requested.
602      *
603      * @return object The object associated with property key. n
604      * ull means no such key-value pair.
605      *
606      * @exception StandardException Standard exception policy.
607      **/

608     Serializable JavaDoc getProperty(
609     TransactionController tc,
610     String JavaDoc key)
611         throws StandardException
612     {
613         //
614
//Try service properties first.
615
if(PropertyUtil.isServiceProperty(key)) return serviceProperties.getProperty(key);
616
617         // See if I'm the exclusive owner. If so I cannot populate
618
// the cache as it would contain my uncommitted changes.
619
if (iHoldTheUpdateLock(tc))
620         {
621             //
622
//Return the property value if it is defined.
623
Serializable JavaDoc v = readProperty(tc,key);
624             if (v != null) return v;
625
626             return getPropertyDefault(tc,key);
627         }
628         else
629         {
630             return getCachedProperty(tc,key);
631         }
632     }
633
634     /**
635      * Get the default for a property.
636      * @exception StandardException Standard exception policy.
637      */

638     Serializable JavaDoc getPropertyDefault(TransactionController tc, String JavaDoc key)
639          throws StandardException
640     {
641         // See if I'm the exclusive owner. If so I cannot populate
642
// the cache as it would contain my uncommitted changes.
643
if (iHoldTheUpdateLock(tc))
644         {
645             //
646
//Return the property default value (may be null) if
647
//defined.
648
Dictionary defaults = (Dictionary)readProperty(tc,AccessFactoryGlobals.DEFAULT_PROPERTY_NAME);
649             if (defaults == null)
650                 return null;
651             else
652                 return (Serializable JavaDoc)defaults.get(key);
653         }
654         else
655         {
656             return getCachedPropertyDefault(tc,key,null);
657         }
658     }
659                                     
660     private Dictionary copyValues(Dictionary to, Dictionary from, boolean stringsOnly)
661     {
662         if (from == null) return to;
663         for (Enumeration JavaDoc keys = from.keys(); keys.hasMoreElements(); ) {
664             String JavaDoc key = (String JavaDoc) keys.nextElement();
665             Object JavaDoc value = from.get(key);
666             if ((value instanceof String JavaDoc) || !stringsOnly)
667                 to.put(key, value);
668         }
669         return to;
670     }
671
672     /**
673         Fetch the set of properties as a Properties object. This means
674         that only keys that have String values will be included.
675     */

676     Properties JavaDoc getProperties(TransactionController tc) throws StandardException {
677         Properties JavaDoc p = new Properties JavaDoc();
678         getProperties(tc,p,true/*stringsOnly*/,false/*!defaultsOnly*/);
679         return p;
680     }
681
682     public void getProperties(TransactionController tc,
683                                Dictionary d,
684                                boolean stringsOnly,
685                                boolean defaultsOnly) throws StandardException
686     {
687         // See if I'm the exclusive owner. If so I cannot populate
688
// the cache as it would contain my uncommitted changes.
689
if (iHoldTheUpdateLock(tc))
690         {
691             Dictionary dbProps = readDbProperties(tc);
692             Dictionary defaults = (Dictionary)dbProps.get(AccessFactoryGlobals.DEFAULT_PROPERTY_NAME);
693             copyValues(d,defaults,stringsOnly);
694             if (!defaultsOnly)copyValues(d,dbProps,stringsOnly);
695         }
696         else
697         {
698             Dictionary dbProps = getCachedDbProperties(tc);
699             Dictionary defaults = (Dictionary)dbProps.get(AccessFactoryGlobals.DEFAULT_PROPERTY_NAME);
700             copyValues(d,defaults,stringsOnly);
701             if (!defaultsOnly)copyValues(d,dbProps,stringsOnly);
702         }
703     }
704
705     void resetCache() {cachedSet = null;}
706
707     /** Read the database properties and add in the service set. */
708     private Dictionary readDbProperties(TransactionController tc)
709          throws StandardException
710     {
711         Dictionary set = new Hashtable();
712
713         // scan the table for a row with no matching "key"
714
ScanController scan = openScan(tc, (String JavaDoc) null, 0);
715
716         DataValueDescriptor[] row = makeNewTemplate();
717
718         while (scan.fetchNext(row)) {
719
720             Object JavaDoc key = ((UserType) row[0]).getObject();
721             Object JavaDoc value = ((UserType) row[1]).getObject();
722             if (SanityManager.DEBUG) {
723                 if (!(key instanceof String JavaDoc))
724                     SanityManager.THROWASSERT(
725                         "Key is not a string " + key.getClass().getName());
726             }
727             set.put(key, value);
728         }
729         scan.close();
730
731         // add the known properties from the service properties set
732
for (int i = 0; i < PropertyUtil.servicePropertyList.length; i++) {
733             String JavaDoc value =
734                 serviceProperties.getProperty(PropertyUtil.servicePropertyList[i]);
735             if (value != null) set.put(PropertyUtil.servicePropertyList[i], value);
736         }
737         return set;
738     }
739
740     private Dictionary getCachedDbProperties(TransactionController tc)
741          throws StandardException
742     {
743         Dictionary dbProps = cachedSet;
744         //Get the cached set of properties.
745
if (dbProps == null)
746         {
747             dbProps = readDbProperties(tc);
748             cachedSet = dbProps;
749         }
750         
751         return dbProps;
752     }
753
754     /** Lock the database properties for an update. */
755     void lockProperties(TransactionController tc) throws StandardException
756     {
757         // lock the property set until the transaction commits.
758
// This allows correct operation of the cache. The cache remains
759
// valid for all transactions except the one that is modifying
760
// it. Thus readers see the old uncommited values. When this
761
// thread releases its exclusive lock the cached is cleared
762
// and the next reader will re-populate the cache.
763
Object JavaDoc csGroup = tc.getLockObject();
764         lf.lockObject(csGroup, csGroup, cachedLock, ShExQual.EX, C_LockFactory.TIMED_WAIT);
765     }
766
767     /**
768       Return true if the caller holds the exclusive update lock on the
769       property conglomerate.
770       */

771     private boolean iHoldTheUpdateLock(TransactionController tc) throws StandardException
772     {
773         Object JavaDoc csGroup = tc.getLockObject();
774         return lf.isLockHeld(csGroup, csGroup, cachedLock, ShExQual.EX);
775     }
776 }
777
778 /**
779     Only used for exclusive lock purposes.
780 */

781 class CacheLock extends ShExLockable {
782
783     private PropertyConglomerate pc;
784
785     CacheLock(PropertyConglomerate pc) {
786         this.pc = pc;
787     }
788
789     public void unlockEvent(Latch lockInfo)
790     {
791         super.unlockEvent(lockInfo);
792         pc.resetCache();
793     }
794 }
795
Popular Tags