Source Code Cross Referenced for StoredClassCatalog.java in  » JMX » je » com » sleepycat » bind » serial » 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 » JMX » je » com.sleepycat.bind.serial 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*-
002:         * See the file LICENSE for redistribution information.
003:         *
004:         * Copyright (c) 2000,2008 Oracle.  All rights reserved.
005:         *
006:         * $Id: StoredClassCatalog.java,v 1.46.2.2 2008/01/07 15:14:05 cwl Exp $
007:         */
008:
009:        package com.sleepycat.bind.serial;
010:
011:        import java.io.ByteArrayInputStream;
012:        import java.io.ByteArrayOutputStream;
013:        import java.io.IOException;
014:        import java.io.ObjectInputStream;
015:        import java.io.ObjectOutputStream;
016:        import java.io.ObjectStreamClass;
017:        import java.io.Serializable;
018:        import java.math.BigInteger;
019:        import java.util.HashMap;
020:
021:        import com.sleepycat.compat.DbCompat;
022:        import com.sleepycat.je.Cursor;
023:        import com.sleepycat.je.CursorConfig;
024:        import com.sleepycat.je.Database;
025:        import com.sleepycat.je.DatabaseConfig;
026:        import com.sleepycat.je.DatabaseEntry;
027:        import com.sleepycat.je.DatabaseException;
028:        import com.sleepycat.je.EnvironmentConfig;
029:        import com.sleepycat.je.LockMode;
030:        import com.sleepycat.je.OperationStatus;
031:        import com.sleepycat.je.Transaction;
032:        import com.sleepycat.util.RuntimeExceptionWrapper;
033:        import com.sleepycat.util.UtfOps;
034:
035:        /**
036:         * A <code>ClassCatalog</code> that is stored in a <code>Database</code>.
037:         *
038:         * <p>A single <code>StoredClassCatalog</code> object is normally used along
039:         * with a set of databases that stored serialized objects.</p>
040:         *
041:         * @author Mark Hayes
042:         */
043:        public class StoredClassCatalog implements  ClassCatalog {
044:
045:            /*
046:             * Record types ([key] [data]):
047:             *
048:             * [0] [next class ID]
049:             * [1 / class ID] [ObjectStreamClass (class format)]
050:             * [2 / class name] [ClassInfo (has 8 byte class ID)]
051:             */
052:            private static final byte REC_LAST_CLASS_ID = (byte) 0;
053:            private static final byte REC_CLASS_FORMAT = (byte) 1;
054:            private static final byte REC_CLASS_INFO = (byte) 2;
055:
056:            private static final byte[] LAST_CLASS_ID_KEY = { REC_LAST_CLASS_ID };
057:
058:            private Database db;
059:            private HashMap classMap;
060:            private HashMap formatMap;
061:            private LockMode writeLockMode;
062:            private boolean cdbMode;
063:            private boolean txnMode;
064:
065:            /**
066:             * Creates a catalog based on a given database. To save resources, only a
067:             * single catalog object should be used for each unique catalog database.
068:             *
069:             * @param database an open database to use as the class catalog.  It must
070:             * be a BTREE database and must not allow duplicates.
071:             *
072:             * @throws DatabaseException if an error occurs accessing the database.
073:             *
074:             * @throws IllegalArgumentException if the database is not a BTREE database
075:             * or if it configured to allow duplicates.
076:             */
077:            public StoredClassCatalog(Database database)
078:                    throws DatabaseException, IllegalArgumentException {
079:
080:                db = database;
081:                DatabaseConfig dbConfig = db.getConfig();
082:                EnvironmentConfig envConfig = db.getEnvironment().getConfig();
083:
084:                writeLockMode = (DbCompat.getInitializeLocking(envConfig) || envConfig
085:                        .getTransactional()) ? LockMode.RMW : LockMode.DEFAULT;
086:                cdbMode = DbCompat.getInitializeCDB(envConfig);
087:                txnMode = dbConfig.getTransactional();
088:
089:                if (!DbCompat.isTypeBtree(dbConfig)) {
090:                    throw new IllegalArgumentException(
091:                            "The class catalog must be a BTREE database.");
092:                }
093:                if (DbCompat.getSortedDuplicates(dbConfig)
094:                        || DbCompat.getUnsortedDuplicates(dbConfig)) {
095:                    throw new IllegalArgumentException(
096:                            "The class catalog database must not allow duplicates.");
097:                }
098:
099:                /*
100:                 * Create the class format and class info maps. Note that these are not
101:                 * synchronized, and therefore the methods that use them are
102:                 * synchronized.
103:                 */
104:                classMap = new HashMap();
105:                formatMap = new HashMap();
106:
107:                DatabaseEntry key = new DatabaseEntry(LAST_CLASS_ID_KEY);
108:                DatabaseEntry data = new DatabaseEntry();
109:                if (dbConfig.getReadOnly()) {
110:                    /* Check that the class ID record exists. */
111:                    OperationStatus status = db.get(null, key, data, null);
112:                    if (status != OperationStatus.SUCCESS) {
113:                        throw new IllegalStateException(
114:                                "A read-only catalog database may not be empty");
115:                    }
116:                } else {
117:                    /* Add the initial class ID record if it doesn't exist.  */
118:                    data.setData(new byte[1]); // zero ID
119:                    /* Use putNoOverwrite to avoid phantoms. */
120:                    db.putNoOverwrite(null, key, data);
121:                }
122:            }
123:
124:            // javadoc is inherited
125:            public synchronized void close() throws DatabaseException {
126:
127:                if (db != null) {
128:                    db.close();
129:                }
130:                db = null;
131:                formatMap = null;
132:                classMap = null;
133:            }
134:
135:            // javadoc is inherited
136:            public synchronized byte[] getClassID(ObjectStreamClass classFormat)
137:                    throws DatabaseException, ClassNotFoundException {
138:
139:                ClassInfo classInfo = getClassInfo(classFormat);
140:                return classInfo.getClassID();
141:            }
142:
143:            // javadoc is inherited
144:            public synchronized ObjectStreamClass getClassFormat(byte[] classID)
145:                    throws DatabaseException, ClassNotFoundException {
146:
147:                return getClassFormat(classID, new DatabaseEntry());
148:            }
149:
150:            /**
151:             * Internal function for getting the class format.  Allows passing the
152:             * DatabaseEntry object for the data, so the bytes of the class format can
153:             * be examined afterwards.
154:             */
155:            private ObjectStreamClass getClassFormat(byte[] classID,
156:                    DatabaseEntry data) throws DatabaseException,
157:                    ClassNotFoundException {
158:
159:                /* First check the map and, if found, add class info to the map. */
160:
161:                BigInteger classIDObj = new BigInteger(classID);
162:                ObjectStreamClass classFormat = (ObjectStreamClass) formatMap
163:                        .get(classIDObj);
164:                if (classFormat == null) {
165:
166:                    /* Make the class format key. */
167:
168:                    byte[] keyBytes = new byte[classID.length + 1];
169:                    keyBytes[0] = REC_CLASS_FORMAT;
170:                    System.arraycopy(classID, 0, keyBytes, 1, classID.length);
171:                    DatabaseEntry key = new DatabaseEntry(keyBytes);
172:
173:                    /* Read the class format. */
174:
175:                    OperationStatus status = db.get(null, key, data,
176:                            LockMode.DEFAULT);
177:                    if (status != OperationStatus.SUCCESS) {
178:                        throw new ClassNotFoundException(
179:                                "Catalog class ID not found");
180:                    }
181:                    try {
182:                        ObjectInputStream ois = new ObjectInputStream(
183:                                new ByteArrayInputStream(data.getData(), data
184:                                        .getOffset(), data.getSize()));
185:                        classFormat = (ObjectStreamClass) ois.readObject();
186:                    } catch (IOException e) {
187:                        throw new RuntimeExceptionWrapper(e);
188:                    }
189:
190:                    /* Update the class format map. */
191:
192:                    formatMap.put(classIDObj, classFormat);
193:                }
194:                return classFormat;
195:            }
196:
197:            /**
198:             * Get the ClassInfo for a given class name, adding it and its
199:             * ObjectStreamClass to the database if they are not already present, and
200:             * caching both of them using the class info and class format maps.  When a
201:             * class is first loaded from the database, the stored ObjectStreamClass is
202:             * compared to the current ObjectStreamClass loaded by the Java class
203:             * loader; if they are different, a new class ID is assigned for the
204:             * current format.
205:             */
206:            private ClassInfo getClassInfo(ObjectStreamClass classFormat)
207:                    throws DatabaseException, ClassNotFoundException {
208:
209:                /*
210:                 * First check for a cached copy of the class info, which if
211:                 * present always contains the class format object
212:                 */
213:                String className = classFormat.getName();
214:                ClassInfo classInfo = (ClassInfo) classMap.get(className);
215:                if (classInfo != null) {
216:                    return classInfo;
217:                } else {
218:                    /* Make class info key.  */
219:                    char[] nameChars = className.toCharArray();
220:                    byte[] keyBytes = new byte[1 + UtfOps
221:                            .getByteLength(nameChars)];
222:                    keyBytes[0] = REC_CLASS_INFO;
223:                    UtfOps.charsToBytes(nameChars, 0, keyBytes, 1,
224:                            nameChars.length);
225:                    DatabaseEntry key = new DatabaseEntry(keyBytes);
226:
227:                    /* Read class info.  */
228:                    DatabaseEntry data = new DatabaseEntry();
229:                    OperationStatus status = db.get(null, key, data,
230:                            LockMode.DEFAULT);
231:                    if (status != OperationStatus.SUCCESS) {
232:                        /*
233:                         * Not found in the database, write class info and class
234:                         * format.
235:                         */
236:                        classInfo = putClassInfo(new ClassInfo(), className,
237:                                key, classFormat);
238:                    } else {
239:                        /*
240:                         * Read class info to get the class format key, then read class
241:                         * format.
242:                         */
243:                        classInfo = new ClassInfo(data);
244:                        DatabaseEntry formatData = new DatabaseEntry();
245:                        ObjectStreamClass storedClassFormat = getClassFormat(
246:                                classInfo.getClassID(), formatData);
247:
248:                        /*
249:                         * Compare the stored class format to the current class format,
250:                         * and if they are different then generate a new class ID.
251:                         */
252:                        if (!areClassFormatsEqual(storedClassFormat,
253:                                getBytes(formatData), classFormat)) {
254:                            classInfo = putClassInfo(classInfo, className, key,
255:                                    classFormat);
256:                        }
257:
258:                        /* Update the class info map.  */
259:                        classInfo.setClassFormat(classFormat);
260:                        classMap.put(className, classInfo);
261:                    }
262:                }
263:                return classInfo;
264:            }
265:
266:            /**
267:             * Assign a new class ID (increment the current ID record), write the
268:             * ObjectStreamClass record for this new ID, and update the ClassInfo
269:             * record with the new ID also.  The ClassInfo passed as an argument is the
270:             * one to be updated.
271:             */
272:            private ClassInfo putClassInfo(ClassInfo classInfo,
273:                    String className, DatabaseEntry classKey,
274:                    ObjectStreamClass classFormat) throws DatabaseException,
275:                    ClassNotFoundException {
276:
277:                /* An intent-to-write cursor is needed for CDB. */
278:                CursorConfig cursorConfig = null;
279:                if (cdbMode) {
280:                    cursorConfig = new CursorConfig();
281:                    DbCompat.setWriteCursor(cursorConfig, true);
282:                }
283:                Cursor cursor = null;
284:                Transaction txn = null;
285:                try {
286:                    if (txnMode) {
287:                        txn = db.getEnvironment().beginTransaction(null, null);
288:                    }
289:                    cursor = db.openCursor(txn, cursorConfig);
290:
291:                    /* Get the current class ID. */
292:                    DatabaseEntry key = new DatabaseEntry(LAST_CLASS_ID_KEY);
293:                    DatabaseEntry data = new DatabaseEntry();
294:                    OperationStatus status = cursor.getSearchKey(key, data,
295:                            writeLockMode);
296:                    if (status != OperationStatus.SUCCESS) {
297:                        throw new IllegalStateException(
298:                                "Class ID not initialized");
299:                    }
300:                    byte[] idBytes = getBytes(data);
301:
302:                    /* Increment the ID by one and write the updated record.  */
303:                    idBytes = incrementID(idBytes);
304:                    data.setData(idBytes);
305:                    cursor.put(key, data);
306:
307:                    /*
308:                     * Write the new class format record whose key is the ID just
309:                     * assigned.
310:                     */
311:                    byte[] keyBytes = new byte[1 + idBytes.length];
312:                    keyBytes[0] = REC_CLASS_FORMAT;
313:                    System.arraycopy(idBytes, 0, keyBytes, 1, idBytes.length);
314:                    key.setData(keyBytes);
315:
316:                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
317:                    ObjectOutputStream oos;
318:                    try {
319:                        oos = new ObjectOutputStream(baos);
320:                        oos.writeObject(classFormat);
321:                    } catch (IOException e) {
322:                        throw new RuntimeExceptionWrapper(e);
323:                    }
324:                    data.setData(baos.toByteArray());
325:
326:                    cursor.put(key, data);
327:
328:                    /*
329:                     * Write the new class info record, using the key passed in; this
330:                     * is done last so that a reader who gets the class info record
331:                     * first will always find the corresponding class format record.
332:                     */
333:                    classInfo.setClassID(idBytes);
334:                    classInfo.toDbt(data);
335:
336:                    cursor.put(classKey, data);
337:
338:                    /*
339:                     * Update the maps before closing the cursor, so that the cursor
340:                     * lock prevents other writers from duplicating this entry.
341:                     */
342:                    classInfo.setClassFormat(classFormat);
343:                    classMap.put(className, classInfo);
344:                    formatMap.put(new BigInteger(idBytes), classFormat);
345:                    return classInfo;
346:                } finally {
347:                    if (cursor != null) {
348:                        cursor.close();
349:                    }
350:                    if (txn != null) {
351:                        txn.commit();
352:                    }
353:                }
354:            }
355:
356:            private static byte[] incrementID(byte[] key) {
357:
358:                BigInteger id = new BigInteger(key);
359:                id = id.add(BigInteger.valueOf(1));
360:                return id.toByteArray();
361:            }
362:
363:            /**
364:             * Holds the class format key for a class, maintains a reference to the
365:             * ObjectStreamClass.  Other fields can be added when we need to store more
366:             * information per class.
367:             */
368:            private static class ClassInfo implements  Serializable {
369:
370:                private byte[] classID;
371:                private transient ObjectStreamClass classFormat;
372:
373:                ClassInfo() {
374:                }
375:
376:                ClassInfo(DatabaseEntry dbt) {
377:
378:                    byte[] data = dbt.getData();
379:                    int len = data[0];
380:                    classID = new byte[len];
381:                    System.arraycopy(data, 1, classID, 0, len);
382:                }
383:
384:                void toDbt(DatabaseEntry dbt) {
385:
386:                    byte[] data = new byte[1 + classID.length];
387:                    data[0] = (byte) classID.length;
388:                    System.arraycopy(classID, 0, data, 1, classID.length);
389:                    dbt.setData(data);
390:                }
391:
392:                void setClassID(byte[] classID) {
393:
394:                    this .classID = classID;
395:                }
396:
397:                byte[] getClassID() {
398:
399:                    return classID;
400:                }
401:
402:                ObjectStreamClass getClassFormat() {
403:
404:                    return classFormat;
405:                }
406:
407:                void setClassFormat(ObjectStreamClass classFormat) {
408:
409:                    this .classFormat = classFormat;
410:                }
411:            }
412:
413:            /**
414:             * Return whether two class formats are equal.  This determines whether a
415:             * new class format is needed for an object being serialized.  Formats must
416:             * be identical in all respects, or a new format is needed.
417:             */
418:            private static boolean areClassFormatsEqual(
419:                    ObjectStreamClass format1, byte[] format1Bytes,
420:                    ObjectStreamClass format2) {
421:                try {
422:                    if (format1Bytes == null) { // using cached format1 object
423:                        format1Bytes = getObjectBytes(format1);
424:                    }
425:                    byte[] format2Bytes = getObjectBytes(format2);
426:                    return java.util.Arrays.equals(format2Bytes, format1Bytes);
427:                } catch (IOException e) {
428:                    return false;
429:                }
430:            }
431:
432:            /*
433:             * We can return the same byte[] for 0 length arrays.
434:             */
435:            private static byte[] ZERO_LENGTH_BYTE_ARRAY = new byte[0];
436:
437:            private static byte[] getBytes(DatabaseEntry dbt) {
438:                byte[] b = dbt.getData();
439:                if (b == null) {
440:                    return null;
441:                }
442:                if (dbt.getOffset() == 0 && b.length == dbt.getSize()) {
443:                    return b;
444:                }
445:                int len = dbt.getSize();
446:                if (len == 0) {
447:                    return ZERO_LENGTH_BYTE_ARRAY;
448:                } else {
449:                    byte[] t = new byte[len];
450:                    System.arraycopy(b, dbt.getOffset(), t, 0, t.length);
451:                    return t;
452:                }
453:            }
454:
455:            private static byte[] getObjectBytes(Object o) throws IOException {
456:
457:                ByteArrayOutputStream baos = new ByteArrayOutputStream();
458:                ObjectOutputStream oos = new ObjectOutputStream(baos);
459:                oos.writeObject(o);
460:                return baos.toByteArray();
461:            }
462:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.