Hello - long time no see :wave: I’ve not been usi...
# cfml-general
t
Hello - long time no see 👋 I’ve not been using CF actively for a while, but I recently unearthed my final year degree project from 1999 and thought about getting it working again. I’ve spun up Lucee using CommandBox, and the code still runs, however the data is stored in an old MS Access (.mdb) file - not sure whether it’s Access 95 or 97. I’ve tried using the UCanAccess jdbc driver, following the blog post by Michael Born here: https://michaelborn.me/entry/creating-an-ms-access-lucee-extension With the jar files in
PROJECT_ROOT/lib
and the following in my Application.cfc…
Copy code
component {
	this.javaSettings.loadPaths = [ "./lib/" ];

	this.datasources["ds_name"] = {
		class: 'net.ucanaccess.jdbc.UcanaccessDriver',
		connectionString: 'jdbc:<ucanaccess://PATH/TO/DB.MDB>,
	};
}
… I get a
Lucee 5.3.10.120 Error (java.lang.NoClassDefFoundError)
exception. 1. Has anyone successfully got Lucee working with UCanAccess and an Access file of that version (95 or 97)? 2. Otherwise, is there another driver I could use, or 3. Does anyone have an old Windows PC with Access 97 or 2000, who could import and convert the database 😉 ? Thanks in advance for any tips or help 🙂
j
Hi - I'm not sure if you have access to MS Excel, but if you do, it looks like you can import the data into that then do with it what you'd like: https://www.excel-easy.com/examples/import-access-data.html
t
Thanks Jim - I’ll see if I can use Excel to do that 👍
Both Excel and Access give “Unrecognised database format” 😞
😖 1
t
does the
java.lang.NoClassDefFoundError
tell you what it cant find? it could be a transient dependency rather the driver itself
t
Copy code
lucee.runtime.exp.NativeException: com/healthmarketscience/jackcess/util/ErrorHandler
  at java.base/java.lang.Class.getDeclaredConstructors0(Native Method)
  at java.base/java.lang.Class.privateGetDeclaredConstructors(Class.java:3137)
  at java.base/java.lang.Class.getConstructor0(Class.java:3342)
  at java.base/java.lang.Class.getConstructor(Class.java:2151)
  at lucee.commons.lang.ClassUtil.newInstance(ClassUtil.java:967)
  at lucee.runtime.db.DataSourceSupport._initializeDriver(DataSourceSupport.java:172)
  at lucee.runtime.db.DataSourceSupport.initialize(DataSourceSupport.java:164)
  at lucee.runtime.db.DataSourceSupport.getConnection(DataSourceSupport.java:103)
  at lucee.runtime.db.DatasourceConnectionPool.loadDatasourceConnection(DatasourceConnectionPool.java:158)
  at lucee.runtime.db.DatasourceConnectionPool.getDatasourceConnection(DatasourceConnectionPool.java:119)
  at lucee.runtime.db.DatasourceManagerImpl.getConnection(DatasourceManagerImpl.java:82)
  at lucee.runtime.tag.Query.executeDatasoure(Query.java:1120)
  at lucee.runtime.tag.Query._doEndTag(Query.java:700)
  at lucee.runtime.tag.Query.doEndTag(Query.java:566)
  at lucee.runtime.functions.query.QueryExecute.call(QueryExecute.java:86)
☝️ That’s the start of the stack trace. Seems someone else in this slack had a similar issue in 2019.
t
it should tell you what class is missing somewhere in the trace or the caused by
b
@mborn What's the status on the ucanaccess project?
m
I wrote this in 2018 (wrong date on my blog post) for my old employer in order to export an Access DB to MySQL.
It worked for me then, haven't used it since.
👍 1
Could be a classloader issue. Could be something I did wrong with the extension.
b
@timbeadle There maybe value in looking for an Access to MySQL converter so you can skip the Access connectivity all together
m
I suspect it would be more reliable using Javaloader.
b
I did that years ago on some very old projects of mine which I had written in Access
t
Hi @mborn - thanks for the detailed writeup. I didn’t use the extension as it doesn’t look like it’s available on forgebox.io any more.
Thanks Brad - that might be a good avenue of investigation.
m
@timbeadle Hmm, yeah I may have even taken it down since I was having trouble with it years ago and couldn't get it working.
👍 1
Also worth noting, @timbeadle,that "the start of the stack trace" is kinda useless for debugging these ClassDefNotFound errors. You'd have to paste the entire stack trace. Lucee often wraps or obfuscates java exceptions, but if you scroll to the end you may see a "Reason" or "Caused By" mentioning the exact class that couldn't load.
1
i.e. is this class the one the failed to load? Or is it the class used to throw an error when some dependency could not be found?
Copy code
com/healthmarketscience/jackcess/util/ErrorHandler
t
Yeah, fair enough. Whole trace incoming…
Actually, it does look like the ErrorHandler is the not found class:
Copy code
Caused by: java.lang.ClassNotFoundException: com.healthmarketscience.jackcess.util.ErrorHandler not found by ucanaccess.3.0.7 [50]
m
Ok, that's more clear then.
It sorta looks to me like an issue with Lucee's reflection not finding the constructor method, even though it found the ErrorHandler class itself. The stack trace clearly shows Lucee is looking for the constructor, and I bet that means it already has the class instance to look on.
b
It's worth noting that an exception raised during the constructor of a class will give you the "real" error the first time you run the code and another generic (not found) sort of error on all subsequent attempts.
🤯 1
I always recommend restarting the server, hitting it ONCE and capturing the FULL STACK TRACE just to be sure.
m
Interesting... I noticed something like this the other day, Brad, when importing the Hibernate extension. The detailed error message only appeared on the first install attempt, and for the second attempt it was like "eh, class not found".
b
Yep, it does that when the code in the actual Java constructor throws an exception. It does some sort of caching where it just never tries to load that class again
m
Ah! Makes total sense.
t
OK, I’ll grab a full trace after restarting. FWIW, does it make a difference whether I use UCanAccess v3 or v5? I started with v5, then tried v3 after the error messages mentioned v3.x.x so I wondered whether going for an older version might help with such an ancient db file.
m
You could try both, but I believe my blog post / steps originally used v3 or v4 at the max.
👍 1
Ok, I downloaded my old extension and fired it up. If you look in the Lucee deploy log, you see the real issue: Lucee doesn't like jar files that aren't OSGI bundles.
Copy code
"/home/michael/.CommandBox/server/76C198B7CDF71CB53F5EB9AEE50F898B-ucanaccess/lucee-5.3.10.97/WEB-INF/lucee-server/context/lib/ucanaccess-4.0.4.jar is not a valid bundle!;org.osgi.framework.BundleException: /home/michael/.CommandBox/server/76C198B7CDF71CB53F5EB9AEE50F898B-ucanaccess/lucee-5.3.10.97/WEB-INF/lucee-server/context/lib/ucanaccess-4.0.4.jar is not a valid bundle!
so that's why the extension isn't working.
I would guess Lucee is requiring all jars from extensions to be valid OSGI bundles.
You are not using the extension, though, right?
You're using the jars natively?
t
Ah, ok. Thanks. Is that something that can be resolved? I know nothing about OSGI. Yes, using the jars natively. No extension.
b
So far as I know, Lucee does not require jars to be OSGI bundles. It is supposed to handle normal jars too so long as you're not trying to load them as a bundle
m
Well, it is erroring about the ucanaccess one, so it either expects it to be a bundle or does an OSGI load attempt just in case.
@timbeadle Take a look at the Jackcess jar MANIFEST.MF file: 1. Rename to
.zip
2. Uncompress 3. Open
META-INF/MANIFEST.MF
See all the
Bundle-*
properties in that file? This means that the Jackcess jar is an OSGI bundle, which means it is loaded using a completely different Java class loader than the rest of the app. This means that when ucanaccess tries to reference jackcess, it cannot because the two are operating in completely different "contexts", if you will.
(If I'm understanding it correctly.)
Since the ucanaccess jar is NOT an OSGI bundle, perhaps it has access to load classes from any OSGI bundle? But perhaps not, since this is obviously not working / not the case.
At any rate...
You could try creating an OSGI bundle which imports the jackcess (and other ) dependencies. Basically, just adding
Bundle-Name
,
Bundle-SymbolicName
, and
Import-Package
properties to the
MANIFEST.MF
file and re-zipping as a
.jar
file. But you'd have to manually add each dependency to the
Import-Package
line, and you may also need to manually create OSGI bundles for every other jar I mentioned on my blog post. (Though
commons-logging
,
commons-lang
, and
hsqldb
are already in Lucee, so 🤷)
t
Thanks - I might give that a try.
Update: taking the path of least resistance, and seeing that the data in the database was just lists of things (cars & wheels) that I had images of on the filesystem, I just built CSV files and read & converted them to query objects on app start. Now it’s not crashing due to missing data, the next challenge will be to make the quarter-century old JavaScript/“Dynamic HTML” work 😆
👍 1