Source Code Cross Referenced for PropertyConglomerate.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » impl » store » access » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » db derby 10.2 » org.apache.derby.impl.store.access 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:
003:           Derby - Class org.apache.derby.impl.store.access.PropertyConglomerate
004:
005:           Licensed to the Apache Software Foundation (ASF) under one or more
006:           contributor license agreements.  See the NOTICE file distributed with
007:           this work for additional information regarding copyright ownership.
008:           The ASF licenses this file to you under the Apache License, Version 2.0
009:           (the "License"); you may not use this file except in compliance with
010:           the License.  You may obtain a copy of the License at
011:
012:              http://www.apache.org/licenses/LICENSE-2.0
013:
014:           Unless required by applicable law or agreed to in writing, software
015:           distributed under the License is distributed on an "AS IS" BASIS,
016:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017:           See the License for the specific language governing permissions and
018:           limitations under the License.
019:
020:         */
021:
022:        package org.apache.derby.impl.store.access;
023:
024:        import org.apache.derby.iapi.reference.Attribute;
025:        import org.apache.derby.iapi.reference.Property;
026:        import org.apache.derby.iapi.reference.SQLState;
027:
028:        import org.apache.derby.iapi.types.UserType;
029:        import org.apache.derby.impl.store.access.UTF;
030:        import org.apache.derby.impl.store.access.UTFQualifier;
031:        import org.apache.derby.iapi.services.io.FormatableBitSet;
032:        import org.apache.derby.iapi.services.io.FormatableHashtable;
033:        import org.apache.derby.iapi.services.locks.ShExLockable;
034:        import org.apache.derby.iapi.services.locks.ShExQual;
035:        import org.apache.derby.iapi.services.daemon.Serviceable;
036:        import org.apache.derby.iapi.services.locks.C_LockFactory;
037:        import org.apache.derby.iapi.services.locks.Latch;
038:        import org.apache.derby.iapi.services.locks.LockFactory;
039:        import org.apache.derby.iapi.services.property.PropertyUtil;
040:
041:        import org.apache.derby.iapi.services.monitor.Monitor;
042:        import org.apache.derby.iapi.services.sanity.SanityManager;
043:        import org.apache.derby.iapi.services.io.Formatable;
044:        import org.apache.derby.iapi.error.StandardException;
045:        import org.apache.derby.iapi.sql.dictionary.DataDictionary;
046:        import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
047:        import org.apache.derby.iapi.store.access.AccessFactory;
048:        import org.apache.derby.iapi.store.access.AccessFactoryGlobals;
049:        import org.apache.derby.iapi.store.access.ConglomerateController;
050:        import org.apache.derby.iapi.services.property.PropertyFactory;
051:        import org.apache.derby.iapi.services.property.PropertySetCallback;
052:        import org.apache.derby.iapi.store.access.Qualifier;
053:        import org.apache.derby.iapi.store.access.ScanController;
054:        import org.apache.derby.iapi.store.access.TransactionController;
055:        import org.apache.derby.iapi.store.raw.RawStoreFactory;
056:        import org.apache.derby.iapi.types.DataValueDescriptor;
057:
058:        import java.io.Serializable;
059:        import java.util.Dictionary;
060:        import java.util.Enumeration;
061:        import java.util.Hashtable;
062:        import java.util.Properties;
063:
064:        /**
065:         Stores properties in a congolmerate with complete transactional support.
066:         <p>
067:         The PropertyConglomerate contains one row with 2 columns per property.
068:         Column 0 is the UTF key, and column 1 is the data.
069:         <p>
070:
071:         <p>
072:         The property conglomerate manages the storage of database properties
073:         and thier defaults. Each property is stored as a row in the
074:         PropertyConglomerate 
075:         <OL>
076:         <LI>Column 0 is the UTF key,
077:         <LI>Column 1 is the data.
078:         </OL>
079:         All the property defaults are stored in a single row of the Property
080:         Conglomerate:
081:         <OL>
082:         <LI>Column 0 is the UTF key "derby.defaultPropertyName".
083:         <LI>Column 1 is a FormatableProperties object with one
084:         row per default property.
085:         </OL>
086:         <p>
087:         In general a propery default defines it value if the property
088:         itself is not defined.
089:
090:         <p>
091:         Because the properties conglomerate is stored in a conglomerate
092:         the information it contains is not available before the raw store
093:         runs recovery. To make a small number of properties (listed in
094:         servicePropertyList) available during early boot, this copies
095:         them to services.properties.
096:         **/
097:        class PropertyConglomerate {
098:            protected long propertiesConglomId;
099:            protected Properties serviceProperties;
100:            private LockFactory lf;
101:            private Dictionary cachedSet;
102:            private CacheLock cachedLock;
103:
104:            private PropertyFactory pf;
105:
106:            /* Constructors for This class: */
107:
108:            PropertyConglomerate(TransactionController tc, boolean create,
109:                    Properties serviceProperties, PropertyFactory pf)
110:                    throws StandardException {
111:                this .pf = pf;
112:
113:                if (!create) {
114:                    String id = serviceProperties
115:                            .getProperty(Property.PROPERTIES_CONGLOM_ID);
116:                    if (id == null) {
117:                        create = true;
118:                    } else {
119:                        try {
120:                            propertiesConglomId = Long.valueOf(id).longValue();
121:                        } catch (NumberFormatException nfe) {
122:                            throw Monitor.exceptionStartingModule(nfe);
123:                        }
124:                    }
125:                }
126:
127:                if (create) {
128:                    DataValueDescriptor[] template = makeNewTemplate();
129:
130:                    Properties conglomProperties = new Properties();
131:
132:                    conglomProperties.put(Property.PAGE_SIZE_PARAMETER,
133:                            RawStoreFactory.PAGE_SIZE_STRING);
134:
135:                    conglomProperties.put(
136:                            RawStoreFactory.PAGE_RESERVED_SPACE_PARAMETER,
137:                            RawStoreFactory.PAGE_RESERVED_ZERO_SPACE_STRING);
138:
139:                    propertiesConglomId = tc
140:                            .createConglomerate(AccessFactoryGlobals.HEAP,
141:                                    template, null, conglomProperties,
142:                                    TransactionController.IS_DEFAULT);
143:
144:                    serviceProperties.put(Property.PROPERTIES_CONGLOM_ID, Long
145:                            .toString(propertiesConglomId));
146:                }
147:
148:                this .serviceProperties = serviceProperties;
149:
150:                lf = ((RAMTransaction) tc).getAccessManager().getLockFactory();
151:                cachedLock = new CacheLock(this );
152:
153:                PC_XenaVersion softwareVersion = new PC_XenaVersion();
154:                if (create)
155:                    setProperty(tc,
156:                            DataDictionary.PROPERTY_CONGLOMERATE_VERSION,
157:                            softwareVersion, true);
158:                else
159:                    softwareVersion
160:                            .upgradeIfNeeded(tc, this , serviceProperties);
161:
162:                getCachedDbProperties(tc);
163:            }
164:
165:            /* Private/Protected methods of This class: */
166:
167:            /**
168:             * Create a new PropertyConglomerate row, with values in it.
169:             **/
170:            private DataValueDescriptor[] makeNewTemplate(String key,
171:                    Serializable value) {
172:                DataValueDescriptor[] template = new DataValueDescriptor[2];
173:
174:                template[0] = new UTF(key);
175:                template[1] = new UserType(value);
176:
177:                return (template);
178:            }
179:
180:            /**
181:             * Create a new empty PropertyConglomerate row, to fetch values into.
182:             **/
183:            private DataValueDescriptor[] makeNewTemplate() {
184:                DataValueDescriptor[] template = new DataValueDescriptor[2];
185:
186:                template[0] = new UTF();
187:                template[1] = new UserType();
188:
189:                return (template);
190:            }
191:
192:            /**
193:             * Open a scan on the properties conglomerate looking for "key".
194:             * <p>
195:             * Open a scan on the properties conglomerate qualified to
196:             * find the row with value key in column 0.  Both column 0
197:             * and column 1 are included in the scan list.
198:             *
199:             * @return an open ScanController on the PropertyConglomerate. 
200:             *
201:             * @param tc        The transaction to do the Conglomerate work under.
202:             * @param key       The "key" of the property that is being requested.
203:             * @param open_mode Whether we are setting or getting the property.
204:             *
205:             * @exception  StandardException  Standard exception policy.
206:             **/
207:            private ScanController openScan(TransactionController tc,
208:                    String key, int open_mode) throws StandardException {
209:                Qualifier[][] qualifiers = null;
210:
211:                if (key != null) {
212:                    // Set up qualifier to look for the row with key value in column[0]
213:                    qualifiers = new Qualifier[1][];
214:                    qualifiers[0] = new Qualifier[1];
215:                    qualifiers[0][0] = new UTFQualifier(0, key);
216:                }
217:
218:                // open the scan, clients will do the fetches and close.
219:                ScanController scan = tc.openScan(
220:                        propertiesConglomId,
221:                        false, // don't hold over the commit
222:                        open_mode, TransactionController.MODE_TABLE,
223:                        TransactionController.ISOLATION_SERIALIZABLE,
224:                        (FormatableBitSet) null,
225:                        (DataValueDescriptor[]) null, // start key
226:                        ScanController.NA, qualifiers,
227:                        (DataValueDescriptor[]) null, // stop key
228:                        ScanController.NA);
229:
230:                return (scan);
231:            }
232:
233:            /* Package Methods of This class: */
234:
235:            /**
236:            	Set a property in the conglomerate.
237:
238:             @param	key		The key used to lookup this property.
239:             @param	value	The value to be associated with this key. If null, delete the
240:             					property from the properties list.
241:             */
242:
243:            /**
244:             * Set the default for a property.
245:             * @exception  StandardException  Standard exception policy.
246:             */
247:            void setPropertyDefault(TransactionController tc, String key,
248:                    Serializable value) throws StandardException {
249:                lockProperties(tc);
250:                Serializable valueToSave = null;
251:                //
252:                //If the default is visible we validate apply and map.
253:                //otherwise we just map.
254:                if (propertyDefaultIsVisible(tc, key)) {
255:                    valueToSave = validateApplyAndMap(tc, key, value, false);
256:                } else {
257:                    synchronized (this ) {
258:                        Hashtable defaults = new Hashtable();
259:                        getProperties(tc, defaults, false/*!stringsOnly*/,
260:                                true/*defaultsOnly*/);
261:                        validate(key, value, defaults);
262:                        valueToSave = map(key, value, defaults);
263:                    }
264:                }
265:                savePropertyDefault(tc, key, valueToSave);
266:            }
267:
268:            boolean propertyDefaultIsVisible(TransactionController tc,
269:                    String key) throws StandardException {
270:                lockProperties(tc);
271:                return (readProperty(tc, key) == null);
272:            }
273:
274:            void saveProperty(TransactionController tc, String key,
275:                    Serializable value) throws StandardException {
276:                if (saveServiceProperty(key, value))
277:                    return;
278:
279:                // Do a scan to see if the property already exists in the Conglomerate.
280:                ScanController scan = this .openScan(tc, key,
281:                        TransactionController.OPENMODE_FORUPDATE);
282:
283:                DataValueDescriptor[] row = makeNewTemplate();
284:
285:                if (scan.fetchNext(row)) {
286:                    if (value == null) {
287:                        // A null input value means that we should delete the row
288:
289:                        scan.delete();
290:                    } else {
291:                        // a value already exists, just replace the second columm
292:
293:                        row[1] = new UserType(value);
294:
295:                        scan.replace(row, (FormatableBitSet) null);
296:                    }
297:
298:                    scan.close();
299:                } else {
300:                    // The value does not exist in the Conglomerate.
301:
302:                    scan.close();
303:                    scan = null;
304:
305:                    if (value != null) {
306:                        // not a delete request, so insert the new property.
307:
308:                        row = makeNewTemplate(key, value);
309:
310:                        ConglomerateController cc = tc.openConglomerate(
311:                                propertiesConglomId, false,
312:                                TransactionController.OPENMODE_FORUPDATE,
313:                                TransactionController.MODE_TABLE,
314:                                TransactionController.ISOLATION_SERIALIZABLE);
315:
316:                        cc.insert(row);
317:
318:                        cc.close();
319:                    }
320:                }
321:            }
322:
323:            private boolean saveServiceProperty(String key, Serializable value) {
324:                if (PropertyUtil.isServiceProperty(key)) {
325:                    if (value != null)
326:                        serviceProperties.put(key, value);
327:                    else
328:                        serviceProperties.remove(key);
329:                    return true;
330:                } else {
331:                    return false;
332:                }
333:            }
334:
335:            void savePropertyDefault(TransactionController tc, String key,
336:                    Serializable value) throws StandardException {
337:                if (saveServiceProperty(key, value))
338:                    return;
339:
340:                Dictionary defaults = (Dictionary) readProperty(tc,
341:                        AccessFactoryGlobals.DEFAULT_PROPERTY_NAME);
342:                if (defaults == null)
343:                    defaults = new FormatableHashtable();
344:                if (value == null)
345:                    defaults.remove(key);
346:                else
347:                    defaults.put(key, value);
348:                if (defaults.size() == 0)
349:                    defaults = null;
350:                saveProperty(tc, AccessFactoryGlobals.DEFAULT_PROPERTY_NAME,
351:                        (Serializable) defaults);
352:            }
353:
354:            private Serializable validateApplyAndMap(TransactionController tc,
355:                    String key, Serializable value, boolean dbOnlyProperty)
356:                    throws StandardException {
357:                Dictionary d = new Hashtable();
358:                getProperties(tc, d, false/*!stringsOnly*/, false/*!defaultsOnly*/);
359:                Serializable mappedValue = pf.doValidateApplyAndMap(tc, key,
360:                        value, d, dbOnlyProperty);
361:                //
362:                // RESOLVE: log device cannot be changed on the fly right now
363:                if (key.equals(Attribute.LOG_DEVICE)) {
364:                    throw StandardException
365:                            .newException(SQLState.RAWSTORE_CANNOT_CHANGE_LOGDEVICE);
366:                }
367:
368:                if (mappedValue == null)
369:                    return value;
370:                else
371:                    return mappedValue;
372:            }
373:
374:            /**
375:              Call the property set callbacks to map a proposed property value
376:              to a value to save.
377:              <P>
378:              The caller must run this in a block synchronized on this
379:              to serialize validations with changes to the set of
380:              property callbacks
381:             */
382:            private Serializable map(String key, Serializable value,
383:                    Dictionary set) throws StandardException {
384:                return pf.doMap(key, value, set);
385:            }
386:
387:            /**
388:              Call the property set callbacks to validate a property change
389:              against the property set provided.
390:              <P>
391:              The caller must run this in a block synchronized on this
392:              to serialize validations with changes to the set of
393:              property callbacks
394:             */
395:
396:            private void validate(String key, Serializable value, Dictionary set)
397:                    throws StandardException {
398:                pf.validateSingleProperty(key, value, set);
399:            }
400:
401:            private boolean bootPasswordChange(TransactionController tc,
402:                    String key, Serializable value) throws StandardException {
403:                // first check for boot password  change - we don't put boot password
404:                // in the servicePropertyList because if we do, then we expose the
405:                // boot password in clear text
406:                if (key.equals(Attribute.BOOT_PASSWORD)) {
407:                    // The user is trying to change the secret key.
408:                    // The secret key is never stored in clear text, but we
409:                    // store the encrypted form in the services.properties
410:                    // file.  Swap the secret key with the encrypted form and
411:                    // put that in the services.properties file.
412:                    AccessFactory af = ((TransactionManager) tc)
413:                            .getAccessManager();
414:
415:                    RawStoreFactory rsf = (RawStoreFactory) Monitor
416:                            .findServiceModule(af, RawStoreFactory.MODULE);
417:
418:                    // remove secret key from properties list if possible
419:                    serviceProperties.remove(Attribute.BOOT_PASSWORD);
420:
421:                    value = rsf.changeBootPassword(serviceProperties, value);
422:                    serviceProperties.put(RawStoreFactory.ENCRYPTED_KEY, value);
423:                    return true;
424:                } else {
425:                    return false;
426:                }
427:            }
428:
429:            /**
430:             * Sets the Serializable object associated with a property key.
431:             * <p>
432:             * This implementation turns the setProperty into an insert into the
433:             * PropertyConglomerate conglomerate.
434:             * <p>
435:             * See the discussion of getProperty().
436:             * <p>
437:             * The value stored may be a Formatable object or a Serializable object
438:             * whose class name starts with java.*. This stops arbitary objects being
439:             * stored in the database by class name, which will cause problems in
440:             * obfuscated/non-obfuscated systems.
441:             *
442:             * @param	tc		The transaction to do the Conglomerate work under.
443:             * @param	key		The key used to lookup this property.
444:             * @param	value	The value to be associated with this key. If null,
445:             *                  delete the property from the properties list.
446:             *
447:             * @exception  StandardException  Standard exception policy.
448:             **/
449:            void setProperty(TransactionController tc, String key,
450:                    Serializable value, boolean dbOnlyProperty)
451:                    throws StandardException {
452:                if (SanityManager.DEBUG) {
453:
454:                    if (!((value == null) || (value instanceof  Formatable))) {
455:                        if (!(value.getClass().getName().startsWith("java."))) {
456:                            SanityManager
457:                                    .THROWASSERT("Non-formattable, non-java class - "
458:                                            + value.getClass().getName());
459:                        }
460:                    }
461:                }
462:
463:                lockProperties(tc);
464:                Serializable valueToValidateAndApply = value;
465:                //
466:                //If we remove a property we validate and apply its default.
467:                if (value == null)
468:                    valueToValidateAndApply = getPropertyDefault(tc, key);
469:                Serializable valueToSave = validateApplyAndMap(tc, key,
470:                        valueToValidateAndApply, dbOnlyProperty);
471:
472:                //
473:                //if this is a bootPasswordChange we save it in
474:                //a special way.
475:                if (bootPasswordChange(tc, key, value))
476:                    return;
477:
478:                //
479:                //value==null means we are removing a property.
480:                //To remove the property we call saveProperty with
481:                //a null value. Note we avoid saving the mapped
482:                //DEFAULT value returned by validateAndApply.
483:                else if (value == null)
484:                    saveProperty(tc, key, null);
485:                //
486:                //value != null means we simply save the possibly
487:                //mapped value of the property returned by
488:                //validateAndApply.
489:                else
490:                    saveProperty(tc, key, valueToSave);
491:            }
492:
493:            private Serializable readProperty(TransactionController tc,
494:                    String key) throws StandardException {
495:                // scan the table for a row with matching "key"
496:                ScanController scan = openScan(tc, key, 0);
497:
498:                DataValueDescriptor[] row = makeNewTemplate();
499:
500:                // did we find at least one row?
501:                boolean isThere = scan.fetchNext(row);
502:
503:                scan.close();
504:
505:                if (!isThere)
506:                    return null;
507:
508:                return (Serializable) (((UserType) row[1]).getObject());
509:            }
510:
511:            private Serializable getCachedProperty(TransactionController tc,
512:                    String key) throws StandardException {
513:                //
514:                //Get the cached set of properties.
515:                Dictionary dbProps = getCachedDbProperties(tc);
516:
517:                //
518:                //Return the value if it is defined.
519:                if (dbProps.get(key) != null)
520:                    return (Serializable) dbProps.get(key);
521:                else
522:                    return getCachedPropertyDefault(tc, key, dbProps);
523:            }
524:
525:            private Serializable getCachedPropertyDefault(
526:                    TransactionController tc, String key, Dictionary dbProps)
527:                    throws StandardException {
528:                //
529:                //Get the cached set of properties.
530:                if (dbProps == null)
531:                    dbProps = getCachedDbProperties(tc);
532:                //
533:                //return the default for the value if it is defined.
534:                Dictionary defaults = (Dictionary) dbProps
535:                        .get(AccessFactoryGlobals.DEFAULT_PROPERTY_NAME);
536:                if (defaults == null)
537:                    return null;
538:                else
539:                    return (Serializable) defaults.get(key);
540:            }
541:
542:            /**
543:             * Gets the de-serialized object associated with a property key.
544:             * <p>
545:             * The Store provides a transaction protected list of database properties.
546:             * Higher levels of the system can store and retrieve these properties
547:             * once Recovery has finished. Each property is a serializable object
548:             * and is stored/retrieved using a String key.
549:             * <p>
550:             * In this implementation a lookup is done on the PropertyConglomerate
551:             * conglomerate, using a scan with "key" as the qualifier.
552:             * <p>
553:             * @param tc      The transaction to do the Conglomerate work under.
554:             * @param key     The "key" of the property that is being requested.
555:             *
556:             * @return object The object associated with property key. n
557:             *                ull means no such key-value pair.
558:             *
559:             * @exception  StandardException  Standard exception policy.
560:             **/
561:            Serializable getProperty(TransactionController tc, String key)
562:                    throws StandardException {
563:                //
564:                //Try service properties first.
565:                if (PropertyUtil.isServiceProperty(key))
566:                    return serviceProperties.getProperty(key);
567:
568:                // See if I'm the exclusive owner. If so I cannot populate
569:                // the cache as it would contain my uncommitted changes.
570:                if (iHoldTheUpdateLock(tc)) {
571:                    //
572:                    //Return the property value if it is defined.
573:                    Serializable v = readProperty(tc, key);
574:                    if (v != null)
575:                        return v;
576:
577:                    return getPropertyDefault(tc, key);
578:                } else {
579:                    return getCachedProperty(tc, key);
580:                }
581:            }
582:
583:            /**
584:             * Get the default for a property.
585:             * @exception  StandardException  Standard exception policy.
586:             */
587:            Serializable getPropertyDefault(TransactionController tc, String key)
588:                    throws StandardException {
589:                // See if I'm the exclusive owner. If so I cannot populate
590:                // the cache as it would contain my uncommitted changes.
591:                if (iHoldTheUpdateLock(tc)) {
592:                    //
593:                    //Return the property default value (may be null) if
594:                    //defined.
595:                    Dictionary defaults = (Dictionary) readProperty(tc,
596:                            AccessFactoryGlobals.DEFAULT_PROPERTY_NAME);
597:                    if (defaults == null)
598:                        return null;
599:                    else
600:                        return (Serializable) defaults.get(key);
601:                } else {
602:                    return getCachedPropertyDefault(tc, key, null);
603:                }
604:            }
605:
606:            private Dictionary copyValues(Dictionary to, Dictionary from,
607:                    boolean stringsOnly) {
608:                if (from == null)
609:                    return to;
610:                for (Enumeration keys = from.keys(); keys.hasMoreElements();) {
611:                    String key = (String) keys.nextElement();
612:                    Object value = from.get(key);
613:                    if ((value instanceof  String) || !stringsOnly)
614:                        to.put(key, value);
615:                }
616:                return to;
617:            }
618:
619:            /**
620:            	Fetch the set of properties as a Properties object. This means
621:            	that only keys that have String values will be included.
622:             */
623:            Properties getProperties(TransactionController tc)
624:                    throws StandardException {
625:                Properties p = new Properties();
626:                getProperties(tc, p, true/*stringsOnly*/, false/*!defaultsOnly*/);
627:                return p;
628:            }
629:
630:            public void getProperties(TransactionController tc, Dictionary d,
631:                    boolean stringsOnly, boolean defaultsOnly)
632:                    throws StandardException {
633:                // See if I'm the exclusive owner. If so I cannot populate
634:                // the cache as it would contain my uncommitted changes.
635:                if (iHoldTheUpdateLock(tc)) {
636:                    Dictionary dbProps = readDbProperties(tc);
637:                    Dictionary defaults = (Dictionary) dbProps
638:                            .get(AccessFactoryGlobals.DEFAULT_PROPERTY_NAME);
639:                    copyValues(d, defaults, stringsOnly);
640:                    if (!defaultsOnly)
641:                        copyValues(d, dbProps, stringsOnly);
642:                } else {
643:                    Dictionary dbProps = getCachedDbProperties(tc);
644:                    Dictionary defaults = (Dictionary) dbProps
645:                            .get(AccessFactoryGlobals.DEFAULT_PROPERTY_NAME);
646:                    copyValues(d, defaults, stringsOnly);
647:                    if (!defaultsOnly)
648:                        copyValues(d, dbProps, stringsOnly);
649:                }
650:            }
651:
652:            void resetCache() {
653:                cachedSet = null;
654:            }
655:
656:            /** Read the database properties and add in the service set. */
657:            private Dictionary readDbProperties(TransactionController tc)
658:                    throws StandardException {
659:                Dictionary set = new Hashtable();
660:
661:                // scan the table for a row with no matching "key"
662:                ScanController scan = openScan(tc, (String) null, 0);
663:
664:                DataValueDescriptor[] row = makeNewTemplate();
665:
666:                while (scan.fetchNext(row)) {
667:
668:                    Object key = ((UserType) row[0]).getObject();
669:                    Object value = ((UserType) row[1]).getObject();
670:                    if (SanityManager.DEBUG) {
671:                        if (!(key instanceof  String))
672:                            SanityManager.THROWASSERT("Key is not a string "
673:                                    + key.getClass().getName());
674:                    }
675:                    set.put(key, value);
676:                }
677:                scan.close();
678:
679:                // add the known properties from the service properties set
680:                for (int i = 0; i < PropertyUtil.servicePropertyList.length; i++) {
681:                    String value = serviceProperties
682:                            .getProperty(PropertyUtil.servicePropertyList[i]);
683:                    if (value != null)
684:                        set.put(PropertyUtil.servicePropertyList[i], value);
685:                }
686:                return set;
687:            }
688:
689:            private Dictionary getCachedDbProperties(TransactionController tc)
690:                    throws StandardException {
691:                Dictionary dbProps = cachedSet;
692:                //Get the cached set of properties.
693:                if (dbProps == null) {
694:                    dbProps = readDbProperties(tc);
695:                    cachedSet = dbProps;
696:                }
697:
698:                return dbProps;
699:            }
700:
701:            /** Lock the database properties for an update. */
702:            void lockProperties(TransactionController tc)
703:                    throws StandardException {
704:                // lock the property set until the transaction commits.
705:                // This allows correct operation of the cache. The cache remains
706:                // valid for all transactions except the one that is modifying
707:                // it. Thus readers see the old uncommited values. When this
708:                // thread releases its exclusive lock the cached is cleared
709:                // and the next reader will re-populate the cache.
710:                Object csGroup = tc.getLockObject();
711:                lf.lockObject(csGroup, csGroup, cachedLock, ShExQual.EX,
712:                        C_LockFactory.TIMED_WAIT);
713:            }
714:
715:            /**
716:              Return true if the caller holds the exclusive update lock on the
717:              property conglomerate.
718:             */
719:            private boolean iHoldTheUpdateLock(TransactionController tc)
720:                    throws StandardException {
721:                Object csGroup = tc.getLockObject();
722:                return lf.isLockHeld(csGroup, csGroup, cachedLock, ShExQual.EX);
723:            }
724:        }
725:
726:        /**
727:         Only used for exclusive lock purposes.
728:         */
729:        class CacheLock extends ShExLockable {
730:
731:            private PropertyConglomerate pc;
732:
733:            CacheLock(PropertyConglomerate pc) {
734:                this .pc = pc;
735:            }
736:
737:            public void unlockEvent(Latch lockInfo) {
738:                super.unlockEvent(lockInfo);
739:                pc.resetCache();
740:            }
741:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.