We're using BerkelyDB within our application.
I did not look too hard for an OSGI module for it, it wasn't readily apparent,
so I just hamfisted one by taking their jar and using bnd to create a bundle
from it.
But there's a curious issue.
We have code like this:
final DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setTransactional(false);
dbConfig.setAllowCreate(allowCreate);
dbConfig.setReadOnly(readOnly);
dbConfig.setDeferredWrite(true);
dbConfig.setBtreeComparator(new KeyComparator());
But when I call this:
this.queueDatabase = dbEnv.openDatabase(null, queueName, dbConfig);
I get a Class Not Found exception. It can not find the KeyComparator class
(which is a local class to this class that's starting the DB).
Well, it seems from a glance at the stack trace, that the BDB is serializing
the comparator, and trying to read it back.
Caused by: com.sleepycat.je.EnvironmentFailureException: (JE 18.3.12) Exception
while trying to load BtreeComparator UNEXPECTED_EXCEPTION: Unexpected internal
Exception, may have side effects.
at
com.sleepycat.je.EnvironmentFailureException.unexpectedException(EnvironmentFailureException.java:384)
at com.sleepycat.je.dbi.DatabaseImpl.bytesToObject(DatabaseImpl.java:1957)
at
com.sleepycat.je.dbi.DatabaseImpl$ComparatorReader.<init>(DatabaseImpl.java:2002)
at com.sleepycat.je.dbi.DatabaseImpl.initWithEnvironment(DatabaseImpl.java:390)
at com.sleepycat.je.dbi.DatabaseImpl.<init>(DatabaseImpl.java:247)
at com.sleepycat.je.dbi.DbTree.doCreateDb(DbTree.java:593)
at com.sleepycat.je.dbi.DbTree.createDb(DbTree.java:486)
at com.sleepycat.je.Database.initNew(Database.java:174)
at com.sleepycat.je.Environment.setupDatabase(Environment.java:864)
at com.sleepycat.je.Environment.openDatabase(Environment.java:668)
at com.qpoint.caterwaul.connect.queue.BDBQueue.<init>(BDBQueue.java:88)
at com.qpoint.caterwaul.connect.queue.BDBQueue.<init>(BDBQueue.java:52)
at com.qpoint.caterwaul.connect.queue.RichBDBQueue.<init>(RichBDBQueue.java:49)
at
com.qpoint.caterwaul.connect.queue.TickEventOrchestrator.start(TickEventOrchestrator.java:87)
at com.qpoint.caterwaul.connect.core.CWCore.initialize(CWCore.java:168)
... 9 more
Caused by: java.lang.ClassNotFoundException:
com.qpoint.caterwaul.connect.queue.KeyComparator
at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:488)
at java.base/java.lang.Class.forName(Class.java:467)
at com.sleepycat.util.ClassResolver$Stream.resolveClass(ClassResolver.java:74)
at
java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2058)
at
java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1922)
at
java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2248)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1757)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:538)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:496)
at com.sleepycat.je.dbi.DatabaseImpl.bytesToObject(DatabaseImpl.java:1954)
... 22 more
We see that it's calling the ObjectInputStream readObject. Which means it
serialized the KeyComparator instance somewhere.
Now, I can't fathom why this is happening, seems an odd decision, but it's
clear to me that it's trying to do this from within the BDB bundle, and ITS
classloader, rather than the bundle classloader where it's being initialized.
That would explain why it can't find the class.
So, do I need to somehow tweak the BDB bundle to import the KeyComparator
class? Won't this be a circular dependency (my module depends on BDB which
depends on my module), unless, of course, I break out my KeyComparator class
into -- I don't know what I would break it into, seems a bit much to make it
its own bundle.
While the solution would be appreciated, how are problems like this approached?
I imagine there's rules of thumb or a top 5 "do this kind of thing" that is
used to approach classpath issues with OSGI and Karaf.
Thanks so much.
Regards,
Will Hartung