Hi,

It looks like that you have listed all the options. I am just thinking that, whether we could configure the parentClassLoader with ext or app by default, which is compatibile with the Geronimo 2.* classloader hierarchy. Maybe someone could help to explain that.

Thanks for bringing this, which is definitely useful for other members.


2013/7/4 Andy McCright <j.andrew.mccright@gmail.com>
Another two options:
4) Update the JAVA_OPTS in the geronimo scripts to include:
-Xbootclasspath/a:$JAVA_HOME/jre/lib/ext/javascript.jar   # linux
-Xbootclasspath/a:%JAVA_HOME%\jre\lib\ext\javascript.jar  # windows

This is only used on the IBM JDK and has the effect of appending the javascript.jar to the boot classloader's classpath - essentially reverting the JDK change.  I'd like to hear more about why the JDK changed before using this option, but it might be more convenient.

5) Do nothing - or maybe just document that if users see this issue on Java 7, that they should add the "osgi.parentClassloader=ext" line to their system.properties file.

Thanks, Andy


On Wed, Jul 3, 2013 at 11:38 AM, Andy McCright <j.andrew.mccright@gmail.com> wrote:
Hi All,

I have noticed that IBM has changed the classloader used to load com.sun.* (specifically com.sun.script.javascript) classes in JDK 7.  In JDK 6, these classes were loaded by the JVM's boot classloader - in JDK 7, they are loaded via the JVM's ext classloader (a child classloader of the boot loader).  This change has the effect of breaking servlet code like this:


        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");
        if(engine == null) {
         throw new RuntimeException("Oh no, unable to find a script engine found for JavaScript");
        }

When running Geronimo 3.0.1 on JDK 6, this code works (engine is non-null, no exception is thrown).  When I switch to JDK7, I see:
ScriptEngineManager providers.next(): javax.script.ScriptEngineFactory: Provider com.sun.script.javascript.RhinoScriptEngineFactory not found
java.lang.RuntimeException: Oh no, unable to find a script engine found for JavaScript
    at org.apache.jsp.HelloWorld_jsp._jspService(HelloWorld_jsp.java:96)
    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.geronimo.tomcat.GeronimoStandardContext$SystemMethodValve.invoke(GeronimoStandardContext.java:731)
    at org.apache.geronimo.tomcat.valve.GeronimoBeforeAfterValve.invoke(GeronimoBeforeAfterValve.java:48)
    at org.apache.geronimo.tomcat.valve.ProtectedTargetValve.invoke(ProtectedTargetValve.java:53)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at org.apache.geronimo.pool.ThreadPool$1.run(ThreadPool.java:267)
    at org.apache.geronimo.pool.ThreadPool$ContextClassLoaderRunnable.run(ThreadPool.java:397)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1121)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
    at java.lang.Thread.run(Thread.java:769)

The reason this fails is that the bundle's classloader's parent loader is the JVM's boot classloader, not the ext loader - so it cannot load the com.sun.* classes that it needs (and that it could in JDK6).

One solution to this is to add the following line to <geronimo_home>/etc/system.properties:
osgi.parentClassloader=ext

This forces the bundle's to search the ext loader (in addition to the boot loader) on boot delegated loads.

I'm wondering if there should be a more permanent fix...  here are a few suggestions:
1) Work with the JDK teams to revert back to the old behavior - I have a ticket open with JDK support, but they apparently moved the com.sun.* classes to the ext loader for a security issue, so it may be a hard sell to get them to move it back.
2) Update the default system.properties to include osgi.parentClassloader=ext
3) Modify the ClassLoaderHook's getBundleClassLoaderParent() method to return the ext loader ( ClassLoader.getSystemClassLoader().getParent() ).

If #1 is not an option, then I think I like optino #2 better than #3, as it allows users to change it easily if they want a different behavior.

Does anybody have strong opinions?  Or other suggestions?

Thanks, Andy




--
Ivan