Installation
cau-repl can be built in one of two flavors
- the standard build is an MIT-licensed universal Java agent that can be used with any Java application
- the GPL build is also a MyCoRe plugin, in addition to the Java agent functionality of the standard build
Universal Java Agent
Compiling
Compile cau-repl as a universal Java agent with Maven:
mvn clean package
# alternatively, if you would also like to run the integration test:
# mvn clean install
This will produce the following two JARs:
target/cau-repl-X.Y.Z-fatjar-mit.jar
can be used as a standalone Java agent and contains all of cau-repls dependenciestarget/cau-repl-agent-X.Y.Z.jar
is an optional lightweight loader-only agent that can be used to load the fullfatjar
into a specific classloader. Use this if your application places its classes in a non-default classloader (e.g. web applications in a servlet container). See the Classloader Selection section for details.
Loading the Agent
To simply get access to the SSH REPL, load cau-repl as a Java agent. You need to pass a special parameter to your Java command:
java -javaagent:/path/to/cau-repl-X.Y.Z-fatjar-mit.jar ...
This also allows you to compile your own classes and use them in the REPL.
If you would like to extend your own classes' availability to the entire application (and not just the REPL), they need to be loaded into the system-default classloader. Then you should configure cau-repl like this:
java -javaagent:/path/to/cau-repl-X.Y.Z-fatjar-mit.jar -DCAU.Groovy.UseSystemClassLoader=true ...
If you use the system-default classloader and loading your classes fails with an exception, you might also need to disable the access protection provided by Java's module system (potentially impacting your target's security if it depends on it). Whether this step is necessary, depends on your target application:
java -javaagent:/path/to/cau-repl-X.Y.Z-fatjar-mit.jar --add-opens 'java.base/java.lang=ALL-UNNAMED' -DCAU.Groovy.UseSystemClassLoader=true ...
The REPL will listen for SSH connections on port 8512 on the local interface. You can use any username to log in. A per-session password will be printed to STDERR on startup. Be careful to make sure that it does not end up in a public logfile, e.g. Systemd's journal. Any local user who can read this password can connect to the REPL and execute code with the permissions of your application. To secure your installation permanently, see the Configuration section for ways to set your own static password without producing log output. The configuration section also describes various parameters that you can use to customize ports, directories, etc.
By default, cau-repl will store its state in the cau-repl
directory, which it will create in the current working
directory.
If you do not see your application's classes in the REPL, you need to load cau-repl into a specific classloader.
Classloader Selection
To load cau-repl in a specific classloader of your application, place cau-repl-X.Y.Z-fatjar-noglp.jar
in your
application's classpath and use the lightweight loader JAR cau-repl-agent-X.Y.Z.jar
as the agent. You can then
configure the loader agent to place the main JAR into the same classloader that your application uses. Just identify
a package or class that your target application will load and pass its resource path as a parameter to the loader agent:
# use the classloader that loads the first class from the org.example.* package
java -javagent:/path/to/cau-repl-agent-X.Y.Z.jar -DCAU.JavaAgent.Triggers=org/example/
# use the classloader that loads the class org.example.SomeClass
java -javagent:/path/to/cau-repl-agent-X.Y.Z.jar -DCAU.JavaAgent.Triggers=org/example/SomeClass
As before, you might also have to set the --add-opens 'java.base/java.lang=ALL-UNNAMED'
parameter if you plan on
changing or adding classes in your target. Note that this will have security implications for your target application if it
depends on the separation provided by Java's module system.
Remark: it is currently not possible to patch the class that the agent triggers on (by the time it is seen, it is too late to block it). So make sure to select a trigger that triggers in the correct classloader, but before the first class you would like to patch.
An Alternative Method for Loading: the Chainloader
If you'd rather not add a -javaagent
to your JVM, there is an alternative way of loading cau-repl
: the chainloader.
The general idea is to replace the main class of your target application with the chainloader class of cau-repl
. The
chainloader can then take care of initializing the REPL and start your target application after it's done. You may
optionally make this apply permanently to your target application's .jar
, but you don't have to.
If at all possible, you should prefer the Java Agent instead of the chainloader, because only the agent has the ability to select a specific classloader. The chainloader can only target the system default classloader.
To start your application with the chainloader, you simply need to arrange for the main .jar
of cau-repl
to be in your
class path. Then start your target application the way you usually would, with two important differences:
- Set the main class to be executed to
de.uni_kiel.rz.fdr.repl.REPLChainloader
instead. This class is contained in the.jar
file ofcau-repl
. This is typically achieved by changing your Java command line appropriately. - Set the system property
CAU.ChainLoader.Class
to your target application's original main class. TheREPLChainloader
will start this class'main
method after it has set up the REPL. The usual way to set this property is to add an argument to the JVM's command line, e.g.-DCAU.ChainLoader.Class=org.example.SomeClass
You may also add further property definitions to the command line to configure the REPL, as you would with the normal agent.
# start an application whose main class is org.example.SomeClass with the chainloader
java -cp /path/to/cau-repl.jar;/other/paths -DCAU.ChainLoader.Class=org.example.SomeClass -DCAU.REPL.SSH.ListenPort=5554 de.uni_kiel.rz.fdr.repl.REPLChainloader
If your target application comes packaged in a .jar
, you have two options for starting it with the chainloader:
To use the chainloader without making any changes to your target's .jar
, proceed as in the example above and
do not use Java's -jar
parameter to start your target, because this would hardwire Java to use the target application's
main class. Instead, add your target's .jar
file to the classpath (-cp
) and start the REPLChainloader
class instead.
You may determine the main class of your target's .jar
file by looking at its META-INF/MANIFEST.MF
file after
unpacking the .jar
.
# start example.jar with its main class org.example.SomeClass with the chainloader
java -cp /path/to/cau-repl.jar;/path/to/example.jar -DCAU.ChainLoader.Class=org.example.SomeClass -DCAU.REPL.SSH.ListenPort=5554 de.uni_kiel.rz.fdr.repl.REPLChainloader
To install the agent's chainloader (semi-)permanently to you target's jar instead, so the REPL is automatically started when you
launch the target's .jar
, use the chainloader installer of cau-repl
:
You start the chainloader installer by running
cau-repl-agent-X.Y.Z.jar
(i.e. the -agent .jar
file, not the -fatjar). The installer will add some required
classes for chainloading to your target's .jar
and change its manifest so the chainloader gets started when the target's
.jar
is run. After this, you can start your target's .jar
without any extra parameters and the REPL will always start
automatically. You just need to make sure that cau-repl-X.Y.Z-fatjar.jar
is available at the location you passed to the installer.
All of the usual configuration properties that you have set
before invoking the installer will also be persisted inside the target's .jar
. You do not need to pass them
again when launching it. The only property that will not be saved is CAU.REPL.SSH.Password
. Use
CAU.REPL.SSH.PasswordCommand
instead, or pass the property every time when launching the target .jar
.
# install the chainloader into target.jar to automatically start on port 44443
java -DCAU.REPL.SSH.ListenPort=44443 -jar /path/to/cau-repl-agent-X.Y.Z.jar install /path/to/cau-repl-X.Y.Z-fatjar.jar /path/to/target.jar
# you may now start the target as usual and the REPL will be available.
# make sure that the -fatjar.jar file remains at the same relative location to target.jar as during the installation
java -jar /path/to/target.jar
# update the installation with an additional setting (not clearing previous settings).
# also repeat this every time you install a new version of cau-repl to update the chainloader in the target
java -DCAU.Groovy.SourceDirs=/my/sources -jar /path/to/cau-repl-agent-X.Y.Z.jar install /path/to/cau-repl-X.Y.Z-fatjar.jar /path/to/target.jar
# install the chainloader into target.jar with an absolute reference to the -fatjar.jar file, allowing you to move target.jar
# without moving -fatjar.jar
java -DCAU.REPL.SSH.ListenPort=44443 -jar /path/to/cau-repl-agent-X.Y.Z.jar absinstall /path/to/cau-repl-X.Y.Z-fatjar.jar /path/to/target.jar
# uninstall the chainloader
java -jar /path/to/cau-repl-agent-X.Y.Z.jar uninstall /path/to/target.jar
MyCoRe plugin
Compiling
Compile cau-repl as a MyCoRe plugin with Maven:
mvn -P gpl clean package
# alternatively, if you would also like to run the integration test:
# mvn -P gpl clean install
This will produce the following two JARs:
target/cau-repl-X.Y.Z-fatjar-gpl.jar
can be used as a MyCoRe plugin (and also as a Java agent)target/cau-repl-agent-X.Y.Z.jar
is an optional lightweight loader-only agent that can be used to load the fullfatjar
into a specific classloader. In a MyCoRe context, you would only have to use this if you want to give cau-repl priority over MyCoRe's basic classes in the JVM's class load order. This is only necessary if you want to use cau-repl to patch basic framework classes, so most MyCoRe users do not have to install this JAR.
Loading the Plugin
To load the cau-repl MyCoRe plugin, place the main JAR in your MyCoRe lib/
directory and enable it in your
.properties
file:
cp /path/to/cau-repl-X.Y.Z-fatjar-gpl.jar /path/to/mycore/lib
echo "CAU.REPL.Enabled=true" >> /path/to/mycore/mycore.properties
Then (re-) start your servlet container. The REPL will listen for SSH connections on port 8512 on the localhost. You can
log in with the username administrator
and the corresponding MyCoRe password of the account. See the
Configuration section for more settings that you can customize from your .properties
.
By default, cau-repl will store its state in the cau-repl
subdirectory, which it will create in your MyCoRe
installation's root.
Loading the Plugin Earlier with the Agent
When you patch libraries or define classes, load order is important. The MyCoRe plugin generally tries to load your Groovy classes as early as possible, but when you interact with lower layers of the stack, it is sometimes too late to do anything about that from the plugin. Most users will never have these issues and can skip this step, but if you try to patch a very basic class and fail because it was already loaded, you can add the agent as described here. Please note: these steps are to be performed in addition to the plugin installation steps above. Do not delete ot disable the main JAR.
First copy the loader agent into place:
cp path/to/cau-repl-agent-X.Y.Z.jar /path/to/mycore/lib
Then add it to your servlet container's java arguments. E.g. for Tomcat, you would add something like this to your
bin/setenv.sh
file:
# adjust paths as needed
export JAVA_OPTS="$JAVA_OPTS -javaagent:/path/to/mycore/lib/cau-repl-agent-X.Y.Z.jar -DCAU.JavaAgent.ClassPath=/path/to/mycore/lib/* -DCAU.JavaAgent.SupportMode=true -DCAU.JavaAgent.Triggers=org/mycore/ -DCAU.Groovy.ClassPath=$CATALINA_HOME/lib/*:$CATALINA_HOME/webapps/ROOT/WEB-INF/lib/* -DCAU.Groovy.SourceDirs=/path/to/your/groovy-sources"
From now on, your Groovy sources in the /path/to/your/groovy-sources
directory will be compiled before other MyCoRe
classes, so they can patch any library that MyCoRe uses and are available from the very beginning of the application's
lifecycle. You can continue to use the plugin as usual when you add the agent like this.