In this blog post we will present you the idea behind one of our tools, called Java Worksheet, which we use for development and production maintenance.
Ever since we’ve discovered Scala REPL, SBT Console and Eclipse/IntelliJ Scala Worksheets, we were looking forward to develop a similar tool. Something that will allow us to write prototypes faster and perform analysis during development and monitor and handle special situations in production.
Our first attempt used the Javascript engine that allowed to instantly run Javascript and interact with our Java API, but it had a disadvantage. We’re used to write our Java code inside an IDE and this solution was missing the autocomplete functionality, code validation and we couldn’t debug the Javascript code.
[code language=”java”]
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.eval("print(‘Hello, World’)");
[/code]
Example of running Javascript on JVM.
To overcome those limitations, we came up with the a solution that allows us write Java code inside IDE (we use Netbeans). The idea is the following – the code through the Compile on Save functionality, gets compiled, then through a Java Agent is loaded the into the target java process and executed.
Worksheet project
We write the code that we want to be executed in an IDE. We use a Maven based project during development and an Ant project in production. Ant project is used in production because we do not want to have a local maven repository on the server, and with Ant project type we can specify the jars we need directly. The project’s dependencies/libraries give access to IDE features like code completion and make the compilation of the code possible. Project is configured with Compile on Save enabled.
Java Agent
In order to load the compiled worksheet class in the target VM we developed an agent. The agent receives as input the path to the compiled worksheet class and the full class name.
Agent loads the class into the classloader, creates a new instance and invokes the run method:
[code language=”java”]
public static void agentmain(String agentArgs, Instrumentation inst)
{
String args[] = agentArgs.split(";");
String classFilePath = args[0];
String className = args[1];
try
{
URL[] urls = new URL[]
{
new File(classFilePath).toURI().toURL()
};
// Create a new class loader
URLClassLoader classLoader = new URLClassLoader(urls, parentClassLoader);
Class clazz = Class.forName(className, true, classLoader);
Object instance = clazz.newInstance();
// The worksheet class must have a run method
clazz.getMethod("run").invoke(instance);
}
catch (MalformedURLException | ClassNotFoundException | InstantiationException
| IllegalAccessException | NoSuchMethodException | SecurityException
| IllegalArgumentException | InvocationTargetException ex)
{
logger.error("Couldn’t load or execute worksheet class {}", className, ex);
}
}
[/code]
IDE (Netbeans) plugin
We’ve created a plugin, that allows the user to select a Virtual Machine on which the agent will be loaded, which in his turn loads the workbench class and invokes the run method.
The plugin adds:
- drop box, that displays the list of Virtual Machines running in the current user session:
[code language=”java”]
List<VirtualMachineDescriptor> vmDescriptors = VirtualMachine.list;
[/code] - run button, which loads the agent:
[code language=”java”]
final String agentJar = Classpath.findPathJar(Agent.class);
final VirtualMachine vm = VirtualMachine.attach(pid);
vm.loadAgent(agentJar, classNameAndPathArgs);</li>
[/code]
Usage
As a result we got an useful tool that is being used now in both development and production environments:
- In development we use it mostly for prototyping. Biggest advantage is the lack of necessity to restart the applications, which might take several seconds. It’s enough to write the code and hit the execute button. The code will be compiled, reloaded and executed on the target VM. For common operations like sending JMS messages, performing REST communication, executing JPQL queries and display the results and native SQL, and others, we built several template worksheet classes.
- In production it is used for:
- System analysis – permits us to execute any code, access any DAOs, services, etc. We’re not limited anymore to DB queries and log files and predefined access methods. It’s virtually possible to run any code.
- Exceptional situation handling. In some situations, a developer can immediately handle the issue immediately without waiting for a bug fix and a new update-pack installation