I have been looking in to the behavior of loading classes that have been
deployed.  When the jar is deployed, the server blindly loads the classes,
searching for Geode Functions.  Specifically, walks over the classes in the
jar, loads each one, and checks to see if both Function and Declarable are
implemented.

Because there's nothing done to limit the classes loaded, this can create a
Class Loader leak, causing an OutOfMemoryException: PermGem (or, now with
java 1.8, OutOfMemoryException: Metaspace)

I wanted to experiment with the behavior, so I grabbed a copy of an
OpenSource project (openhtmltopdf) and wrapped it in to a function I could
call via the dev REST API.  Basically, when the function is called, it'll
read in a simple html document and produce a simple PDF from it.

The project has several dependencies, which created the first problem.  It
was necessary to explode both openhtmltopdf-core.jar and
openhtmltopdf-pdfbox.jar out in to my Function's jar.

However, there are also external Apache jars that are required:

   - pdfbox-2.0.3.jar
   - fontbox-2.0.3.jar
   - commons-logging-1.2.jar

If I create an über.jar that contains all of these dependencies and my
Function, then deploy it, I'm able to execute my Function without any
problems.

If I make a small change to the loader to accept a pattern to only actually
load my Function class out of the jar, the rest of the classes are not
automatically loaded.  This causes ClassNotFound and ClassDefNotFound
exceptions.

If I start my sever and provide the 3 Apache libraries with the --classpath
option, and have my jar only contain my Function and the openhtmltopdf
project classes, then when I deploy I'm able to run my function.

Are there any other scenarios to try out to let the class loader load
what's needed rather than having to build these uber jars or specify
dependencies on the server classpath at startup?  I don't know of any way
to dynamically update the classpath once the server is up and running.

Reply via email to