Code Monkey home page Code Monkey logo

jvm-breakglass's Introduction

nRepl hook for Java

Build Status [Clojars Project]

Background on nRepl

Setting up an nrepl can be useful to introspect into the JVM for troubleshouting/investigation or testing of regular Java applications. You can connect onto a process and use a Clojure prompt interactivelly or have client application that sends and execute Java code dynamically. It works because the code injected is Clojure and that the Clojure run-time allows to evaluate code at run-time. Furthermore Clojure interops very easily with Java i.e. you can translate pretty much any Java code into Clojure and access all your Java object from the injected Clojure code. This is the perfect tool to access the inside of your JVM process live after it has been deployed. To run any fancy change of code scenario, any data structure or call any method you don't need to redeploy your java code. You can see what your process sees in real time. This is an unvaluable tool to use to develop and maintain a java application.

What is this project about?

Clojure and REPL can be introduced into a pure Java project to improve troubleshooting without having to force a team to migrate their code away from Java.

nRepl is easy to start in Clojure but it needs a tiny bit of work to inject it into your java process. If you are using Spring and Java, this project has done that for you. This project is a Maven module that you can integrate in your java project and inject easily the Repl in your application.

Watch these videos to get an introduction:

How to install the REPL in your application with Spring

  • insert the dependency inside your maven project
<dependency>
  <groupId>net.matlux</groupId>
  <artifactId>jvm-breakglass</artifactId>
  <version>0.0.8</version>
</dependency>
  • add the following bean to your Spring config
<bean id="repl" class="net.matlux.NreplServerSpring">
  <constructor-arg index="0" value="1112" />
</bean>

1112 is the port number.

What if I don't use Spring?

No problems, just instanciate the following class in your application rather than using the xml spring context:

    import net.matlux.NreplServer;
    new NreplServer(port) //start server listening onto port number
    .put("department",myObject);

Repeat the call to put with as many object as you want to register on the repl. The NreplServer instance is a Map onto which you can add Object instances that you can retreive later on under the repl access.

MBean registration (new in R_0.0.7)

It is also possible to register the NreplServer as MBean for access via a JMX console. The registred MBean is found under the name net.matlux:name=Nrepl. The MBean has the following properties and operations.

Type Name Meaning
Attribute Port Indicates the port used for the nrepl server (read/write).
Attribute Started Indicates wether the NreplServer is started or not (read only).
Operation Start Starts the NreplServer.
Operation Stop Stops the NreplServer.

The registration/unregistration of the NReplServer to the MBeanServer must be done manually via the methods NReplServer#registerMBean and NReplServer#unregisterMBean. If you are using the NReplServer with Spring, these operations are typically preformed post construction and pre destruction.

Quick demonstration of this project

Pre-requisites:

  • You must have leinengen installed. Otherwise follow the installation process on this site.
  • You must have Maven installed. Follow this otherwise.

Tutorial

  • clone this repo and compile the example
    git clone https://github.com/matlux/jvm-breakglass.git
    cd jvm-breakglass/examples/server
  • Compile this project
    mvn clean install
  • Start the example of a server with the NreplServer
    ./startSpringServer.sh

You should now see the following message repeating itself on the screen:

Retrieve Employees from NY or London:
Retrieve Employees from NY or London:
...

Notes: Ctrl-c does not seem to kill the process for some reason. Please find it's PID and kill it with kill -9 [pid of the process] from a different window when you've finished the demonstration.

  • Leave the above server running and open a different shell window before you continue

Notes: You don't need to be inside the current directory of any particular project. Actually it's best to be outside of any project so you don't pull any specific project dependencies and introduce an uncertainty. If in doubt, type cd /tmp to make sure you're outside of any specific Lein project.

  • Start the repl client which introspects into the Java server process
    lein repl :connect localhost:1112
  • Copy and past the following commands
  (use 'cl-java-introspector.spring)
  (use 'cl-java-introspector.core)
  (use 'me.raynes.fs)
  • Type one of the following Commands
  ;list beans
  (get-beans)

  ;find a bean or an object
  (get-bean "department")

  ;what methods or fields has the obj?
  (methods-info  (get-bean "department"))
  • what next?

See more examples.

Quick demonstration of a standard Java Server example

  • clone this repo and compile the example
    git clone https://github.com/matlux/jvm-breakglass.git
    cd jvm-breakglass/examples/server-no-spring
  • Compile this project
    mvn clean install
  • Start the example of a server with the NreplServer
    ./startServer.sh
  • Start the repl client which introspects into the Java server process
    lein repl :connect localhost:1112
  • Copy and past the following commands
  (use 'cl-java-introspector.core)
  (use 'me.raynes.fs)
  • Type one of the following Commands
  ;list objs
  (get-objs)

  ;find a bean or an object
  (get-obj "department")

  ;what methods or fields has the obj?
  (methods-info  (get-obj "departement"))
  • what next?

See section below with more use cases. or See more examples.

There are two type of client to access the nRepl server

Via the repl client with lein

    lein repl :connect [host:port]

for example:

    lein repl :connect localhost:1112

programatically

    (require '[clojure.tools.nrepl :as repl])
    (with-open [conn (repl/connect :port 1112)]
     (-> (repl/client conn 1000)
       (repl/message {:op :eval :code "(+ 1 1)"})
       repl/response-values))

The above sends an expression "(+ 1 1)" to be evaluated remotely. See nrepl website for more details.

Also see quick demo above.

Once you have the nRepl running inside your process. What can you do?

You need to connect onto it with the lein command above and the set of imports (also above). Now you can type any of the following commands.

retrieve the list of System properties from the java process

    (filter #(re-matches #"sun.*" (key %)) (into {} (System/getProperties)))

This example filters on a regex. It retrieves property keys which start with "sun"

list bean or objects

  (get-beans) ; spring example
  (get-objs)  ; standard java example

retrieve a bean or an object by name

  (get-bean "department")  ; spring example
  (get-obj "department")   ; standard java example

keep the object reference

  (def myobj (get-bean "department")) ; spring example
  ;;or
  (def myobj (get-obj "department")) ; standard java example

what methods or fields has the obj?

  (methods-info  myobj)
  (fields-info  myobj)

show the content of the fields the obj

  (to-tree  myobj)

Terminate the process ;)

    (System/exit 0)

Retrieve the Spring application context

    (import '(net.matlux NreplServerSpring))


    (. NreplServerSpring/instance getApplicationContext)

    ;; for example list all the bean names
    (. (. NreplServerSpring/instance getApplicationContext) getBeanDefinitionNames)

Coherence example: Retrieve the number of object in a Cache

Your application needs to have a dependency on Oracle Coherence, The binary and dependency is not provided here, this is just an example.

    (def all-filter (new AlwaysFilter))
    (def nodeCache (Caches/getCache "cachename")
    (let [all-filter (new AlwaysFilter)
      nodeCache (Caches/getCache "cachename")]
    (. (. nodeCache entrySet all-filter) size))

Introspect into a Java bean (not a Spring one this time...)

    (bean obj)

Introspect into a Java Object

    (to-tree myObject)

For example:

        Department department = new Department("The Art Department",0L);
        department.add(new Employee("Bob","Dilan",new Address("1 Mayfair","SW1","London")));
        department.add(new Employee("Mick","Jagger",new Address("1 Time Square",null,"NY")));
        objMap.put("department", department);
        Set<Object> myFriends = new HashSet<Object>();
        myFriends.add(new Employee("Keith","Richard",new Address("2 Mayfair","SW1","London")));
        myFriends.add(new Employee("Nina","Simone",new Address("1 Gerards Street","12300","Smallville")));
        objMap.put("myFriends", myFriends);
        objMap.put("nullValue", null);

becomes

[{objMap {myFriends [{address {city Smallville, zipcode 12300, street 1 Gerards Street}, lastname Simone, firstname Nina} {address {city London, zipcode SW1, street 2 Mayfair}, lastname Richard, firstname Keith}], nullValue nil, department {id 0, name The Art Department, employees [{address {city London, zipcode SW1, street 1 Mayfair}, lastname Dilan, firstname Bob} {address {city NY, zipcode nil, street 1 Time Square}, lastname Jagger, firstname Mick}]}}} nil]

See cl-java-introspector.core for details of the implementation.

License

Copyright (C) 2015 Mathieu Gauthron

Distributed under the Eclipse Public License, the same as Clojure.

jvm-breakglass's People

Contributors

matlux avatar mbonaci avatar methylene avatar sesm avatar stanislas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

jvm-breakglass's Issues

Update docs to recommend require

Should the README recommend require instead of use?

I got the following at the REPL, which seems like it could lead to trouble:

WARNING: name already refers to: #'clojure.core/name in namespace: user, being replaced by: #'me.raynes.fs/name
WARNING: parents already refers to: #'clojure.core/parents in namespace: user, being replaced by: #'me.raynes.fs/parents

lein repl :connect localhost:1112 doesn't work

Hi,

the server throws the following exception:

ERROR: Unhandled REPL handler exception processing message {:id 7e129e42-acf2-4d05-bc27-beedcf66334b, :op clone}
java.lang.NoClassDefFoundError: clojure/tools/nrepl/StdOutBuffer
at clojure.tools.nrepl.middleware.session$session_out.invoke(session.clj:26)
at clojure.tools.nrepl.middleware.session$create_session.invoke(session.clj:118)
at clojure.tools.nrepl.middleware.session$create_session.invoke(session.clj:114)
at clojure.tools.nrepl.middleware.session$session$fn__657.invoke(session.clj:178)
at clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__393.invoke(middleware.clj:17)
at clojure.tools.nrepl.server$handle_STAR_.invoke(server.clj:18)
at clojure.tools.nrepl.server$handle$fn__704.invoke(server.clj:27)
at clojure.core$binding_conveyor_fn$fn__4145.invoke(core.clj:1910)
at clojure.lang.AFn.call(AFn.java:18)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

Logging or not logging or optional logging?

I wonder if the log messages are a little too intrusive?
I wonder if it wouldn't make sense to make them optional or to turn them off?

I have made changes to the code so now the user has a chance to catch a RuntimeException when start,stop,registerMBean and unRegisterMBean fail.

Why do we need to force the logging of the error if we already throw an exception?

For example is it not intrusive to force the logging of a Sever error when we know we're going to catch it further up and manage it in a way which is not dramatic for the application?

Catching exception or not catching the exception? That is the question.

I think it might make sense not to catch the exception when the Server start or stops of or when the MBean registration fails?

What do you think?

Should it be optional?

Should it the exception not probagate by default in order not to mess up the hosting application when this tool is not working properly?

Build on Travis fails from time to time

I had to re-run the build 3 times to get it to pass.

When it happens I'm getting a socket Exception when the test tries to connect onto the REPL to remmotly executing code.

Maven repo?

Great project, thank you for making this available. Is the JAR only on clojars.org? I'd like to use it at work, where we proxy to Maven Central, but not clojars.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.