rlm@10
|
1 ;; Conversions between JMX data structures and idiomatic Clojure
|
rlm@10
|
2 ;; docs in clojure/contrib/jmx.clj!!
|
rlm@10
|
3
|
rlm@10
|
4 ;; by Stuart Halloway
|
rlm@10
|
5
|
rlm@10
|
6 ;; Copyright (c) Stuart Halloway, 2009. All rights reserved. The use
|
rlm@10
|
7 ;; and distribution terms for this software are covered by the Eclipse
|
rlm@10
|
8 ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
rlm@10
|
9 ;; which can be found in the file epl-v10.html at the root of this
|
rlm@10
|
10 ;; distribution. By using this software in any fashion, you are
|
rlm@10
|
11 ;; agreeing to be bound by the terms of this license. You must not
|
rlm@10
|
12 ;; remove this notice, or any other, from this software.
|
rlm@10
|
13
|
rlm@10
|
14
|
rlm@10
|
15 (in-ns 'clojure.contrib.jmx)
|
rlm@10
|
16
|
rlm@10
|
17 (declare jmx->clj)
|
rlm@10
|
18
|
rlm@10
|
19 (defn jmx-url
|
rlm@10
|
20 "Build a JMX URL from options."
|
rlm@10
|
21 ([] (jmx-url {}))
|
rlm@10
|
22 ([overrides]
|
rlm@10
|
23 (let [opts (merge {:host "localhost", :port "3000", :jndi-path "jmxrmi"} overrides)]
|
rlm@10
|
24 (format "service:jmx:rmi:///jndi/rmi://%s:%s/%s" (opts :host) (opts :port) (opts :jndi-path)))))
|
rlm@10
|
25
|
rlm@10
|
26 (defmulti as-object-name
|
rlm@10
|
27 "Interpret an object as a JMX ObjectName."
|
rlm@10
|
28 { :arglists '([string-or-name]) }
|
rlm@10
|
29 class)
|
rlm@10
|
30 (defmethod as-object-name String [n] (ObjectName. n))
|
rlm@10
|
31 (defmethod as-object-name ObjectName [n] n)
|
rlm@10
|
32
|
rlm@10
|
33 (defn composite-data->map [cd]
|
rlm@10
|
34 (into {}
|
rlm@10
|
35 (map (fn [attr] [(keyword attr) (jmx->clj (.get cd attr))])
|
rlm@10
|
36 (.. cd getCompositeType keySet))))
|
rlm@10
|
37
|
rlm@10
|
38 (defn maybe-keywordize
|
rlm@10
|
39 "Convert a string key to a keyword, leaving other types alone. Used to
|
rlm@10
|
40 simplify keys in the tabular data API."
|
rlm@10
|
41 [s]
|
rlm@10
|
42 (if (string? s) (keyword s) s))
|
rlm@10
|
43
|
rlm@10
|
44 (defn maybe-atomize
|
rlm@10
|
45 "Convert a list of length 1 into its contents, leaving other things alone.
|
rlm@10
|
46 Used to simplify keys in the tabular data API."
|
rlm@10
|
47 [k]
|
rlm@10
|
48 (if (and (instance? java.util.List k)
|
rlm@10
|
49 (= 1 (count k)))
|
rlm@10
|
50 (first k)
|
rlm@10
|
51 k))
|
rlm@10
|
52
|
rlm@10
|
53 (defvar simplify-tabular-data-key
|
rlm@10
|
54 (comp maybe-keywordize maybe-atomize))
|
rlm@10
|
55
|
rlm@10
|
56 (defn tabular-data->map [td]
|
rlm@10
|
57 (into {}
|
rlm@10
|
58 ; the need for into-array here was a surprise, and may not
|
rlm@10
|
59 ; work for all examples. Are keys always arrays?
|
rlm@10
|
60 (map (fn [k]
|
rlm@10
|
61 [(simplify-tabular-data-key k) (jmx->clj (.get td (into-array k)))])
|
rlm@10
|
62 (.keySet td))))
|
rlm@10
|
63
|
rlm@10
|
64 (defmulti jmx->clj
|
rlm@10
|
65 "Coerce JMX data structures into Clojure data.
|
rlm@10
|
66 Handles CompositeData, TabularData, maps, and atoms."
|
rlm@10
|
67 { :argslists '([jmx-data-structure]) }
|
rlm@10
|
68 (fn [x]
|
rlm@10
|
69 (cond
|
rlm@10
|
70 (instance? javax.management.openmbean.CompositeData x) :composite
|
rlm@10
|
71 (instance? javax.management.openmbean.TabularData x) :tabular
|
rlm@10
|
72 (instance? clojure.lang.Associative x) :map
|
rlm@10
|
73 :default :default)))
|
rlm@10
|
74 (defmethod jmx->clj :composite [c] (composite-data->map c))
|
rlm@10
|
75 (defmethod jmx->clj :tabular [t] (tabular-data->map t))
|
rlm@10
|
76 (defmethod jmx->clj :map [m] (into {} (zipmap (keys m) (map jmx->clj (vals m)))))
|
rlm@10
|
77 (defmethod jmx->clj :default [obj] obj)
|
rlm@10
|
78
|
rlm@10
|
79 (def guess-attribute-map
|
rlm@10
|
80 {"java.lang.Integer" "int"
|
rlm@10
|
81 "java.lang.Boolean" "boolean"
|
rlm@10
|
82 "java.lang.Long" "long"
|
rlm@10
|
83 })
|
rlm@10
|
84
|
rlm@10
|
85 (defn guess-attribute-typename
|
rlm@10
|
86 "Guess the attribute typename for MBeanAttributeInfo based on the attribute value."
|
rlm@10
|
87 [value]
|
rlm@10
|
88 (let [classname (.getName (class value))]
|
rlm@10
|
89 (get guess-attribute-map classname classname)))
|
rlm@10
|
90
|
rlm@10
|
91 (defn build-attribute-info
|
rlm@10
|
92 "Construct an MBeanAttributeInfo. Normally called with a key/value pair from a Clojure map."
|
rlm@10
|
93 ([attr-name attr-value]
|
rlm@10
|
94 (build-attribute-info
|
rlm@10
|
95 (as-str attr-name)
|
rlm@10
|
96 (guess-attribute-typename attr-value)
|
rlm@10
|
97 (as-str attr-name) true false false))
|
rlm@10
|
98 ([name type desc readable? writable? is?] (MBeanAttributeInfo. name type desc readable? writable? is? )))
|
rlm@10
|
99
|
rlm@10
|
100 (defn map->attribute-infos
|
rlm@10
|
101 "Construct an MBeanAttributeInfo[] from a Clojure associative."
|
rlm@10
|
102 [attr-map]
|
rlm@10
|
103 (into-array (map (fn [[attr-name value]] (build-attribute-info attr-name value))
|
rlm@10
|
104 attr-map)))
|