I am trying to get Markdown with a table extension working on Coldfusion 9. There are several other similar questions regarding CF and Markdown here in stackoverflow, but none of them deal with extensions.
So far I have tried:
- markdownj via javaloader.cfc
- pegdown via javaloader.cfc
- showdownjs via orangepips nice cfc (I would have connected all this but had no reputation for more than 2)
All of them work fine for basic Markdown, but none of them support tables out of the box.
Both pegdown and showdown.js support table expansion. Markdownj however does not want to support him at the moment, but I thought it was worth a try.
I think my problem is the correct syntax for loading the extension in pegdown or showdown. Both work in a completely different way, one of which is pure Java, and the other is Javascript.
For pegdown
My code here is very simple and just uses javaloader to load both pegdown and the required library. This part works fine, with no errors, but when I try to use the pegdown class, I get a pretty general error;
An exception occurred while instantiating a Java object. The class must not be an interface or an abstract class. Error: ''.
Code to call pegdown;
<cfscript> jClass = [ "#getDirectoryFromPath(getCurrentTemplatePath())#/pegdown/pegdown-1.2.1.jar" , "#getDirectoryFromPath(getCurrentTemplatePath())#/pegdown/parboiled-core-1.1.3.jar" ]; javaloader = createObject('component','components.javaloader.JavaLoader').init(jClass, true); variables.pegdown = javaloader.create("org.pegdown.PegDownProcessor"); </cfscript> <cfdump var="#variables.pegdown#" />
For showdownjs:
I tried to add the extension file (extensions / table.js) to var for evaluation and add the var extensions to the converter parameters according to the documentation, but it does not work. I assume that showdown.js does not expect to work inside the main JavaEngineManager script, since the main showdown.js script cannot "see" the extension of the tables without receiving a row of 246 s;
The script had an error: sun.org.mozilla.javascript.internal.JavaScriptException: Extension 'undefined' could not be loaded. It was either not found or is not a valid extension. (
My code for showdown.js is based on Orangepips answer in the related question above.
<cfcomponent output="false" accessors="true"> <cffunction name="init" output="false" access="public" returntype="Showdown" hint="Constructor"> <cfset variables.manager = createObject("java", "javax.script.ScriptEngineManager").init()> <cfset variables.engine = manager.getEngineByName("javascript")> <cfreturn this/> </cffunction> <cffunction name="toHTML" output="false" access="public" returntype="any" hint=""> <cfargument name="markdownText" type="string" required="true"/> <cfset var local = structNew()/> <cfset var bindings = variables.engine.createBindings()> <cfset var result = ""> <cfset var showdownJS = "" /> <cftry> <cfset bindings.put("markdownText", arguments.markdownText)> <cfset variables.engine.setBindings(bindings, createObject("java", "javax.script.ScriptContext").ENGINE_SCOPE)> <cfset showdownJS &= fileRead('#getDirectoryFromPath(getCurrentTemplatePath())#/showdown.js')> <cfset showdownJS &= fileRead('#getDirectoryFromPath(getCurrentTemplatePath())#/extensions/table.js')> <cfset showdownJS &= showdownAdapterJS()> <cfset result = engine.eval(showdownJS)> <cfcatch type="javax.script.ScriptException"> <cfset result = "The script had an error: " & cfcatch.Message> </cfcatch> </cftry> <cfreturn result> </cffunction> <cffunction name="showdownAdapterJS" output="false" access="private" returntype="string" hint=""> <cfset var local = structNew()/> <cfsavecontent variable="local.javascript"> <cfoutput>#chr(13)##chr(10)# var __converter = new Showdown.converter({extensions:['table']}); __converter.makeHtml(markdownText);</cfoutput> </cfsavecontent> <cfreturn local.javascript> </cffunction> </cfcomponent>
I am open to any ideas and have no particular preference for one solution over another.
Stacktrace
java.lang.ClassNotFoundException: org.parboiled.BaseParser at coldfusion.bootstrap.BootstrapClassLoader.loadClass(BootstrapClassLoader.java:235) at java.lang.ClassLoader.loadClass(Unknown Source) at com.compoundtheory.classloader.NetworkClassLoader.loadClass(NetworkClassLoader.java:463) at java.lang.ClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClassInternal(Unknown Source) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(Unknown Source) at java.lang.ClassLoader.defineClass(Unknown Source) at com.compoundtheory.classloader.NetworkClassLoader.loadClass(NetworkClassLoader.java:450) at java.lang.ClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClassInternal(Unknown Source) at java.lang.Class.getDeclaredFields0(Native Method) at java.lang.Class.privateGetDeclaredFields(Unknown Source) at java.lang.Class.privateGetPublicFields(Unknown Source) at java.lang.Class.getFields(Unknown Source) at coldfusion.runtime.java.ObjectHandler.Initialize(ObjectHandler.java:35) at coldfusion.runtime.java.ObjectHandler.<init>(ObjectHandler.java:30) at coldfusion.runtime.java.ReflectionCache$1.fetch(ReflectionCache.java:29) at coldfusion.util.SoftCache.get_statsOff(SoftCache.java:133) at coldfusion.util.SoftCache.get(SoftCache.java:81) at coldfusion.runtime.java.ReflectionCache.get(ReflectionCache.java:36) at coldfusion.runtime.java.JavaProxy.<init>(JavaProxy.java:35) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Unknown Source) at coldfusion.runtime.java.JavaProxy.CreateObject(JavaProxy.java:166) at coldfusion.runtime.java.JavaProxy.invoke(JavaProxy.java:80) at coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2360) at cfJavaLoader2ecfc535209679$funcCREATEJAVAPROXY.runFunction(/srv/vhosts/myproject/httpdocs/components/javaloader/JavaLoader.cfc:329) at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472) at coldfusion.filter.SilentFilter.invoke(SilentFilter.java:47) at coldfusion.runtime.UDFMethod$ReturnTypeFilter.invoke(UDFMethod.java:405) at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368) at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55) at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:321) at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:220) at coldfusion.runtime.CfJspPage._invokeUDF(CfJspPage.java:2582) at cfJavaLoader2ecfc535209679$funcCREATE.runFunction(/srv/vhosts/myproject/httpdocs/components/javaloader/JavaLoader.cfc:87) at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472) at coldfusion.filter.SilentFilter.invoke(SilentFilter.java:47) at coldfusion.runtime.UDFMethod$ReturnTypeFilter.invoke(UDFMethod.java:405) at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368) at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55) at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:321) at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:220) at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:491) at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:337) at coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2360) at cfpegdown2ecfm1473046932.runPage(/srv/vhosts/myproject/httpdocs/_temp/markdown/pegdown.cfm:22) at coldfusion.runtime.CfJspPage.invoke(CfJspPage.java:231) at coldfusion.tagext.lang.IncludeTag.doStartTag(IncludeTag.java:416) at coldfusion.runtime.CfJspPage._emptyTcfTag(CfJspPage.java:2722) at cfApplication2ecfc294205112$funcONREQUEST.runFunction(/srv/vhosts/myproject/httpdocs/Application.cfc:377) at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472) at coldfusion.runtime.UDFMethod$ReturnTypeFilter.invoke(UDFMethod.java:405) at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368) at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55) at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:321) at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:220) at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:491) at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:337) at coldfusion.runtime.AppEventInvoker.invoke(AppEventInvoker.java:88) at coldfusion.runtime.AppEventInvoker.onRequest(AppEventInvoker.java:280) at coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:356) at coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:48) at coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40) at coldfusion.filter.PathFilter.invoke(PathFilter.java:94) at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:70) at coldfusion.filter.BrowserDebugFilter.invoke(BrowserDebugFilter.java:79) at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28) at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38) at coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:46) at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38) at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22) at coldfusion.filter.CachingFilter.invoke(CachingFilter.java:62) at coldfusion.CfmServlet.service(CfmServlet.java:200) at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:89) at jrun.servlet.FilterChain.doFilter(FilterChain.java:86) at com.intergral.fusionreactor.filter.FusionReactorCoreFilter.doRequestNoFilter(FusionReactorCoreFilter.java:712) at com.intergral.fusionreactor.filter.FusionReactorCoreFilter.doFusionRequest(FusionReactorCoreFilter.java:341) at com.intergral.fusionreactor.filter.FusionReactorCoreFilter.doFilter(FusionReactorCoreFilter.java:246) at com.intergral.fusionreactor.filter.FusionReactorFilter.doFilter(FusionReactorFilter.java:121) at jrun.servlet.FilterChain.doFilter(FilterChain.java:94) at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:42) at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:46) at jrun.servlet.FilterChain.doFilter(FilterChain.java:94) at jrun.servlet.FilterChain.service(FilterChain.java:101) at jrun.servlet.ServletInvoker.invoke(ServletInvoker.java:106) at jrun.servlet.JRunInvokerChain.invokeNext(JRunInvokerChain.java:42) at jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:286) at jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:543) at jrun.servlet.jrpp.JRunProxyService.invokeRunnable(JRunProxyService.java:203) at jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:428) at jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)
Update
Now it works thanks to the side dish.
The problem is a lack of understanding of Java and some additional dependencies for PegDown and Parboiled.
Parboiled needs java and core.jars Pegdown. Pegdown expects to find an ASM library
I used version 4.1 and included -all version. The recommendation is to include only the necessary asm banks, but for now this is enough for me to take it further.
Working code for CF9 (running on JRUN / Linux)
<cfset markdownString = fileRead("#getDirectoryFromPath(getCurrentTemplatePath())#/demo.txt")> <cfset jarDir = "#getDirectoryFromPath(getCurrentTemplatePath())#pegdown" /> <cfset jClass = [ "#jarDir#/parboiled-java-1.1.3.jar" , "#jarDir#/asm-all-4.1.jar" , "#jarDir#/parboiled-core-1.1.3.jar" , "#jarDir#/pegdown-1.2.1.jar" ] /> <cfset javaloader = createObject('component','components.javaloader.JavaLoader').init(jClass, false) /> <cfset variables.pegdown = javaloader.create("org.pegdown.PegDownProcessor").init(javaCast("int", InputBaseN("0x20", 16))) /> <cfoutput>#variables.pegdown.markdownToHtml(markdownString)#</cfoutput>