The MS-Access library Jackcess is split into two bundles, a main jackcess and a jackcess-encrypt library. The last one is needed to read encrypted, and possibly password protected MS-Access files.
My code installs the crypto provider as
db = new DatabaseBuilder(new File(pathname))
.setCodecProvider(new CryptCodecProvider())
.open();
This results to having the OSGi bundle in having a dependency to com.healthmarketscience.jackcess.impl, according to the biz.aQute.bnd.builder BND plugin run by my Gradle script. Of course, the Jackcess bundle does not export this package. My assumption is that this is because the parameter from setCodecProvider is a com.healthmarketscience.jackcess.impl.CodecProvider. My own code does not reference the impl package in any way.
I'd prefer to use the two Jackcess bundles as they are, but am I right in assuming this is a packaging or reference error in Jackcess and to solve this I need to repackage the Jackcess bundle, exporting the impl package too?
just so you are aware, you don't need jackcess-encrypt for simple password protection. you only need it for database formats which are actually encrypted in some form.
otherwise, i've never used the osgi support myself, so i'm not surprised there are some issues. it would not be ideal to export the entire impl package, kind of defeats the purpose of the osgi exports (although i assume it would work). ideally, the CodecProvider interface should really be in a separate package.
Last edit: James Ahlborn 2017-04-10
The database itself is not password protected, but the database is encrypted. Without the CryptCodecProvider it cannot be read, with it it can. Technically it would be enough to move the CodecProvider one package up, I guess.
With the CodecProvider in an unexported package the using (my) bundle cannot be resolved by the OSGi framework.
I don't want to export the impl package, as it indeed does defeat the purpose of the OSGi system.
Last edit: M. le Rutte 2017-04-10
Besides having to add the .impl as Export-Package, the crypto implementation itself is in the same package. Eventually I ended up with creating an OSGi jar which includes Jackcess, Jackcess-Crypto and BouncyCastle, where none of the BouncyCastle stuff needs to be exported. I don't think the last part was needed as I had removed all Import-Package instructions.
are you saying that there is more that needs to be fixed, or just pointing out what you did to work around the issue?
Both.
The crypto package should either be moved to a separate package, but more optimally it should be bundled as a bundle fragment, in which case it will augment the original bundle's classloader. The crypto package does not have a need for a standalone deployment, so it is a perfect candidate for a bundle fragment.
The BouncyCastle bundling isn't necesssary as it was a result of too spurious manifest editing.
So, if i just reconfigured jackcess-entrypt into a bundle fragment, would it all "just work"? or do i still need to move some classes into different packages? do you have examples of manifests that work correctly?
Last edit: James Ahlborn 2017-04-17
It appears that I was wrong, the problem is remains that the crypt provider does not have its own namespace.
I made the encrypt bundle a fragment bundle by adding the header Fragment-Host: com.healthmarketscience.jackcess;bundle-version="[2.1.6,3)", and the kept the Export-Package header. Additionally I exported the .impl package from the regular Jackcess bundle.
Unfortunately this doesn't make the CryptCodecProvider visible to my OSGi bundle, which is thus not capable of instantiating the CryptCodecProvider.
so, i was poking at this tonight to see if i could make it go, and it seems like there isn't an easy solution. i wanted to just move CodecProvider to an "spi" package, but i don't think that will work because it depends on PageChannel. since that is in impl, i assume it would still break the osgi mechanism?
So i'm running out ideas here. My latest thought is adding a utility class to jackcess-encrypt. If i added the following utility class to the "public" api of jackcess-encrypt, this should solve your problem, right? Since the public api of this class only depends on the public jackcess api?
Without a clear direction on this, i will probably close it in the near future.
Just noted your update, I guess it would not work as the CryptCodecProvider still would not be visible to the classloader of the bundle. In OSGi each bundle gets its own classloader and that classloader can only access public (exported) classes of another bundle.
Whereas in 'plain' Java jars the entire path becomes a single namespace and multiple jars contributing to the same package become merged, this doesn't happen in OSGi,
but if the CryptCodecUtil class was in the public package of jackcess encrypt, then your code would only be interacting with classes in the public package. that seems like it should work.
I don't have the structure of Jackess in my head to be able to conclude that to be honest. As far as my OSGi knowledge goes the crypto bundle is best off as a fragment to the orignal bundle, as, like I wrote before, there is no need to run the crypto bundle on its own. In that case it will share a classloader, yet the consuming package must be able to access the class. If it can access the CryptCodecUtil then I guess it may work.
Just a small checkup, will it run in Java 9's modular classpath? It seems to have a similar resolution process and doesn't allow split packages anymore.
Last edit: M. le Rutte 2017-09-26
So here's my plan:
i have no idea how java 9 plays into all of this. a quck read of that link makes it sound like everything on the classpath is a single module, so no problems. i guess if you embrace modules, though, there could be problems. java 9 is going to be a migration nightmare for everyone.
Last edit: James Ahlborn 2017-10-03
Ticket moved from /p/jackcess/bugs/140/
fixed in trunk, will be in the 2.1.4 release.