Nikita Fedyashev
Nikita Fedyashev

Reputation: 19048

Is it possible to create writeable bean from Clojure that I can manage from jconsole?

I was exploring Clojure java.jmx API Reference and trying the examples mentioned there e.g.

;; Can I serve my own beans?  Sure, just drop a Clojure ref
;; into an instance of clojure.java.jmx.Bean, and the bean
;; will expose read-only attributes for every key/value pair
;; in the ref:

  (jmx/register-mbean
     (create-bean
     (ref {:string-attribute "a-string"}))
     "my.namespace:name=Value")

It works great, the bean's attribute value is visible in the console but it is read-only.

Is there a way to create a writeable bean(so that it is listed in "Operations" folder and manageable from console)?

Upvotes: 0

Views: 95

Answers (1)

Jochen Bedersdorfer
Jochen Bedersdorfer

Reputation: 4122

It looks like the clojure.java.jmx code supports setAttribute. (see (deftype Bean ...) in https://github.com/clojure/java.jmx/blob/master/src/main/clojure/clojure/java/jmx.clj

The easiest way seems to be just using an atom instead of a ref.

You could then have atom watchers to run some code if JMX changes it. Maybe give that a try. I've forgotten most of JMX ;)

EDIT: Quickly tried it. It looks like the attribute is still read-only :( I gotta look deeper. Nevertheless, the source code is pretty nice and hopefully easy to understand.

EDIT2: The issue is with build-attribute-info which passes false to the writeable? flag in the `MBeanAttributeInfo.

You can monkey patch that:


(import 'java.jmx.MBeanAttributeInfo)
(require '[clojure.java.jmx :as jmx])

(defn build-my-attribute-info
  "Construct an MBeanAttributeInfo. Normally called with a key/value pair from a Clojure map."
  ([attr-name attr-value]
  (build-my-attribute-info
  (name attr-name)
  (.getName (class attr-value)) ;; you might have to map primitive types here
  (name attr-name) true true false)) ;; false -> true compared to orig code
  ([name type desc readable? writable? is?] (println "Build info:" name type readable? writable?) (MBeanAttributeInfo. name type desc readable? writable? is? )))

;; the evil trick one should only use in tests, maybe
;; overwrite the original definition of build-attribute-info with yours
(with-redefs [jmx/build-attribute-info build-my-attribute-info]
   (jmx/register-mbean (jmx/create-bean (atom {:foo "bar"})) "my.bean:name=Foo"))

;; write to it
(jmx/write! "my.bean:name=Foo" "foo" "hello world")

;; read it
(jmx/read "my.bean:name=Foo" "foo")
=> "hello world"

Now, unfortunately, Java Mission Control still can't change the value, but I'm not sure why. The MBean info is correct. Must be a permission thing.

Upvotes: 2

Related Questions