Permalink
Browse files

smaller surface area for public API, use protocols where appropriate

  • Loading branch information...
1 parent d34e999 commit 83665310bf7598371364ae6b51380017f6d1cc01 @stuarthalloway stuarthalloway committed Mar 18, 2011
Showing with 62 additions and 188 deletions.
  1. +1 −0 .gitignore
  2. +56 −49 src/main/clojure/clojure/java/jmx.clj
  3. +5 −139 src/test/clojure/clojure/java/test_jmx.clj
View
1 .gitignore
@@ -0,0 +1 @@
+target/*
View
105 src/main/clojure/clojure/java/jmx.clj
@@ -86,25 +86,23 @@
(let [opts (merge {:host "localhost", :port "3000", :jndi-path "jmxrmi"} overrides)]
(format "service:jmx:rmi:///jndi/rmi://%s:%s/%s" (opts :host) (opts :port) (opts :jndi-path)))))
-(defmulti as-object-name
- "Interpret an object as a JMX ObjectName."
- { :arglists '([string-or-name]) }
- class)
-(defmethod as-object-name String [n] (ObjectName. n))
-(defmethod as-object-name ObjectName [n] n)
-
-(defn composite-data->map [cd]
- (into {}
- (map (fn [attr] [(keyword attr) (jmx->clj (.get cd attr))])
- (.. cd getCompositeType keySet))))
-
-(defn maybe-keywordize
+(defprotocol CoercionImpl
+ (as-object-name [_]))
+
+(extend-protocol CoercionImpl
+ String
+ (as-object-name [_] (ObjectName. _))
+
+ ObjectName
+ (as-object-name [_] _))
+
+(defn- maybe-keywordize
"Convert a string key to a keyword, leaving other types alone. Used to
simplify keys in the tabular data API."
[s]
(if (string? s) (keyword s) s))
-(defn maybe-atomize
+(defn- maybe-atomize
"Convert a list of length 1 into its contents, leaving other things alone.
Used to simplify keys in the tabular data API."
[k]
@@ -113,45 +111,48 @@
(first k)
k))
-(def simplify-tabular-data-key
+(def ^:private simplify-tabular-data-key
(comp maybe-keywordize maybe-atomize))
-(defn tabular-data->map [td]
- (into {}
- ; the need for into-array here was a surprise, and may not
- ; work for all examples. Are keys always arrays?
- (map (fn [k]
- [(simplify-tabular-data-key k) (jmx->clj (.get td (into-array k)))])
- (.keySet td))))
-
-(defmulti jmx->clj
- "Coerce JMX data structures into Clojure data.
- Handles CompositeData, TabularData, maps, and atoms."
- { :argslists '([jmx-data-structure]) }
- (fn [x]
- (cond
- (instance? javax.management.openmbean.CompositeData x) :composite
- (instance? javax.management.openmbean.TabularData x) :tabular
- (instance? clojure.lang.Associative x) :map
- :default :default)))
-(defmethod jmx->clj :composite [c] (composite-data->map c))
-(defmethod jmx->clj :tabular [t] (tabular-data->map t))
-(defmethod jmx->clj :map [m] (into {} (zipmap (keys m) (map jmx->clj (vals m)))))
-(defmethod jmx->clj :default [obj] obj)
-
-(def guess-attribute-map
+(defprotocol Destract
+ (objects->data [_] "Convert JMX object model into data. Handles CompositeData, TabularData, maps, and atoms."))
+
+(extend-protocol Destract
+ javax.management.openmbean.CompositeData
+ (objects->data
+ [cd]
+ (into {}
+ (map (fn [attr] [(keyword attr) (objects->data (.get cd attr))])
+ (.. cd getCompositeType keySet))))
+
+ javax.management.openmbean.TabularData
+ (objects->data
+ [td]
+ (into {}
+ (map (fn [k]
+ [(simplify-tabular-data-key k) (objects->data (.get td (into-array k)))])
+ (.keySet td))))
+ clojure.lang.Associative
+ (objects->data
+ [m]
+ (into {} (zipmap (keys m) (map objects->data (vals m)))))
+
+ Object
+ (objects->data [obj] obj))
+
+(def ^:private guess-attribute-map
{"java.lang.Integer" "int"
"java.lang.Boolean" "boolean"
"java.lang.Long" "long"
})
-(defn guess-attribute-typename
+(defn- guess-attribute-typename
"Guess the attribute typename for MBeanAttributeInfo based on the attribute value."
[value]
(let [classname (.getName (class value))]
(get guess-attribute-map classname classname)))
-(defn build-attribute-info
+(defn- build-attribute-info
"Construct an MBeanAttributeInfo. Normally called with a key/value pair from a Clojure map."
([attr-name attr-value]
(build-attribute-info
@@ -160,7 +161,7 @@
(name attr-name) true false false))
([name type desc readable? writable? is?] (MBeanAttributeInfo. name type desc readable? writable? is? )))
-(defn map->attribute-infos
+(defn- map->attribute-infos
"Construct an MBeanAttributeInfo[] from a Clojure associative."
[attr-map]
(into-array (map (fn [[attr-name value]] (build-attribute-info attr-name value))
@@ -190,9 +191,9 @@
(def read
"Read an mbean property."
- (comp jmx->clj raw-read))
+ (comp objects->data raw-read))
-(defn read-supported
+(defn- read-supported
"Calls read to read an mbean property, *returning* unsupported
operation exceptions instead of throwing them. Used to keep mbean
from blowing up. Note: There is no good exception that aggregates
@@ -203,7 +204,9 @@
(catch Exception e
e)))
-(defn write! [n attr value]
+(defn write!
+ "Write an attribute value."
+ [n attr value]
(.setAttribute
*connection*
(as-object-name n)
@@ -225,18 +228,20 @@
[n]
(.getOperations (mbean-info n)))
-(defn operation
+(defn- operation
"The MBeanOperationInfo for operation op on mbean n. Used by invoke."
[n op]
(first (filter #(= (-> % .getName keyword) op) (operations n))))
-(defn op-param-types
+(defn- op-param-types
"The parameter types (as class name strings) for operation op on n.
Used for invoke."
[n op]
(map #(-> % .getType) (.getSignature (operation n op))))
-(defn register-mbean [mbean mbean-name]
+(defn register-mbean
+ "Register an mbean with the current *connection*."
+ [mbean mbean-name]
(.registerMBean *connection* mbean (as-object-name mbean-name)))
(defn mbean-names
@@ -255,7 +260,9 @@
[n]
(doall (map #(-> % .getName keyword) (operations n))))
-(defn invoke [n op & args]
+(defn invoke
+ "Invoke an operation an an MBean."
+ [n op & args]
(if ( seq args)
(.invoke *connection* (as-object-name n) (name op)
(into-array args)
View
144 src/test/clojure/clojure/java/test_jmx.clj
@@ -1,140 +1,3 @@
-;; Tests for JMX support for Clojure
-
-;; by Stuart Halloway
-
-;; Copyright (c) Stuart Halloway. All rights reserved. The use
-;; and distribution terms for this software are covered by the Eclipse
-;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
-;; which can be found in the file epl-v10.html at the root of this
-;; distribution. By using this software in any fashion, you are
-;; agreeing to be bound by the terms of this license. You must not
-;; remove this notice, or any other, from this software.
-
-(ns clojure.java.test-jmx
- (:import javax.management.openmbean.CompositeDataSupport
- [javax.management MBeanAttributeInfo AttributeList]
- [java.util.logging LogManager Logger])
- (:use clojure.test)
- (:require [clojure.java [jmx :as jmx]]))
-
-
-(defn =set [a b]
- (= (set a) (set b)))
-
-(defn seq-contains-all?
- "Does container contain every item in containee?
- Not fast. Testing use only"
- [container containee]
- (let [container (set container)]
- (every? #(contains? container %) containee)))
-
-(deftest finding-mbeans
- (testing "as-object-name"
- (are [cname object-name]
- (= cname (.getCanonicalName object-name))
- "java.lang:type=Memory" (jmx/as-object-name "java.lang:type=Memory")))
- (testing "mbean-names"
- (are [cnames object-name]
- (= cnames (map #(.getCanonicalName %) object-name))
- ["java.lang:type=Memory"] (jmx/mbean-names "java.lang:type=Memory"))))
-
-; These actual beans may differ on different JVM platforms.
-; Tested April 2010 to work on Sun and IBM JDKs.
-(deftest testing-actual-beans
- (testing "reflecting on capabilities"
- (are [attr-list mbean-name]
- (seq-contains-all? (jmx/attribute-names mbean-name) attr-list)
- [:Verbose :ObjectPendingFinalizationCount :HeapMemoryUsage :NonHeapMemoryUsage] "java.lang:type=Memory")
- (are [op-list mbean-name]
- (seq-contains-all? (jmx/operation-names mbean-name) op-list)
- [:gc] "java.lang:type=Memory"))
- (testing "mbean-from-oname"
- (are [key-names oname]
- (seq-contains-all? (keys (jmx/mbean oname)) key-names)
- [:Verbose :ObjectPendingFinalizationCount :HeapMemoryUsage :NonHeapMemoryUsage] "java.lang:type=Memory")))
-
-(deftest raw-reading-attributes
- (let [mem "java.lang:type=Memory"
- log "java.util.logging:type=Logging"]
- (testing "simple scalar attributes"
- (are [a b] (= a b)
- false (jmx/raw-read mem :Verbose))
- (are [type attr] (instance? type attr)
- Number (jmx/raw-read mem :ObjectPendingFinalizationCount)))))
-
-(deftest reading-attributes
- (testing "simple scalar attributes"
- (are [type attr] (instance? type attr)
- Number (jmx/read "java.lang:type=Memory" :ObjectPendingFinalizationCount)))
- (testing "composite attributes"
- (are [ks attr] (=set ks (keys attr))
- [:used :max :init :committed] (jmx/read "java.lang:type=Memory" :HeapMemoryUsage)))
- (testing "tabular attributes"
- (is (map? (jmx/read "java.lang:type=Runtime" :SystemProperties)))))
-
-(deftest writing-attributes
- (let [mem "java.lang:type=Memory"]
- (jmx/write! mem :Verbose true)
- ;; need boolean cast to fix Boolean object identity error
- (is (true? (boolean (jmx/raw-read mem :Verbose))))
- (jmx/write! mem :Verbose false)))
-
-(deftest test-invoke-operations
- (testing "without arguments"
- (jmx/invoke "java.lang:type=Memory" :gc))
- (testing "with arguments"
- (.addLogger (LogManager/getLogManager) (Logger/getLogger "clojure.java.test_jmx"))
- (jmx/invoke "java.util.logging:type=Logging" :setLoggerLevel "clojure.java.test_jmx" "WARNING")))
-
-(deftest test-jmx->clj
- (testing "it works recursively on maps"
- (let [some-map {:foo (jmx/raw-read "java.lang:type=Memory" :HeapMemoryUsage)}]
- (is (map? (:foo (jmx/jmx->clj some-map))))))
- (testing "it leaves everything else untouched"
- (is (= "foo" (jmx/jmx->clj "foo")))))
-
-
-(deftest test-composite-data->map
- (let [data (jmx/raw-read "java.lang:type=Memory" :HeapMemoryUsage)
- prox (jmx/composite-data->map data)]
- (testing "returns a map with keyword keys"
- (is (= (set [:committed :init :max :used]) (set (keys prox)))))))
-
-(deftest test-tabular-data->map
- (let [raw-props (jmx/raw-read "java.lang:type=Runtime" :SystemProperties)
- props (jmx/tabular-data->map raw-props)]
- (are [k] (contains? props k)
- :java.class.path
- :path.separator)))
-
-(deftest test-creating-attribute-infos
- (let [infos (jmx/map->attribute-infos [[:a 1] [:b 2]])
- info (first infos)]
- (testing "generates the right class"
- (is (= (class (into-array MBeanAttributeInfo [])) (class infos))))
- (testing "generates the right instance data"
- (are [result expr] (= result expr)
- "a" (.getName info)
- "a" (.getDescription info)))))
-
-(deftest various-beans-are-readable
- (testing "that all java.lang beans can be read without error"
- (doseq [mb (jmx/mbean-names "*:*")]
- (is (map? (jmx/mbean mb)) mb))))
-
-(deftest test-jmx-url
- (testing "creates default url"
- (is (= "service:jmx:rmi:///jndi/rmi://localhost:3000/jmxrmi"
- (jmx/jmx-url))))
- (testing "creates custom url"
- (is (= "service:jmx:rmi:///jndi/rmi://example.com:4000/jmxrmi"
- (jmx/jmx-url {:host "example.com" :port 4000}))))
- (testing "creates custom jndi path"
- (is (= "service:jmx:rmi:///jndi/rmi://example.com:4000/jmxconnector"
- (jmx/jmx-url {:host "example.com" :port 4000 :jndi-path "jmxconnector"})))))
-
-;; ----------------------------------------------------------------------
-;; tests for clojure.java.jmx.Bean.
(deftest dynamic-mbean-from-compiled-class
(let [mbean-name "clojure.java.test_jmx:name=Foo"]
@@ -171,8 +34,11 @@
[5 4] (seq atts))))
(deftest test-guess-attribute-typename
- (are [x y] (= x (jmx/guess-attribute-typename y))
-; "long" 10
+ (are [x y] (= x (@#'jmx/guess-attribute-typename y))
+ "long" 10
"boolean" false
"java.lang.String" "foo"
"long" (Long/valueOf (long 10))))
+
+
+

0 comments on commit 8366531

Please sign in to comment.