1 package com.atlassian.plugin.jmx;
2
3 import java.lang.management.ManagementFactory;
4 import java.util.concurrent.atomic.AtomicInteger;
5
6 import javax.management.InstanceNotFoundException;
7 import javax.management.MBeanServer;
8 import javax.management.ObjectName;
9 import javax.management.RuntimeMBeanException;
10
11 import org.hamcrest.Matchers;
12 import org.junit.Before;
13 import org.junit.Rule;
14 import org.junit.Test;
15 import org.junit.rules.ExpectedException;
16
17 import static org.hamcrest.MatcherAssert.assertThat;
18 import static org.hamcrest.Matchers.containsString;
19 import static org.hamcrest.Matchers.instanceOf;
20 import static org.hamcrest.Matchers.is;
21
22 public class TestAbstractJmxBridge
23 {
24 private static final boolean NONDEFAULT_BOOLEAN = true;
25 private static final char NONDEFAULT_CHAR = 'A';
26 private static final byte NONDEFAULT_BYTE = 1;
27 private static final short NONDEFAULT_SHORT = 2;
28 private static final int NONDEFAULT_INT = 3;
29 private static final long NONDEFAULT_LONG = 4;
30 private static final float NONDEFAULT_FLOAT = 5;
31 private static final double NONDEFAULT_DOUBLE = 6;
32 private static final String NONDEFAULT_STRING = "B";
33
34 @Rule
35 public ExpectedException expectedException = ExpectedException.none();
36
37 @SuppressWarnings ("UnusedDeclaration")
38 public interface SampleMXBean
39 {
40 boolean getBoolean();
41
42 char getChar();
43
44 byte getByte();
45
46 short getShort();
47
48 int getInt();
49
50 long getLong();
51
52 float getFloat();
53
54 double getDouble();
55
56 String getString();
57
58 void operation();
59
60 String concat(String left, String right);
61 }
62
63
64
65
66
67
68 private static class SampleJmxBridge extends AbstractJmxBridge<SampleMXBean> implements SampleMXBean
69 {
70
71
72
73 private static final AtomicInteger nextJmxInstance = new AtomicInteger();
74
75 private int operationCount;
76
77 public SampleJmxBridge()
78 {
79 super(JmxUtil.objectName(nextJmxInstance, "Sample"), SampleMXBean.class);
80 }
81
82 @Override
83 protected SampleMXBean getMXBean()
84 {
85 return this;
86 }
87
88 public int getOperationCount()
89 {
90 return operationCount;
91 }
92
93 @Override
94 public boolean getBoolean()
95 {
96 return NONDEFAULT_BOOLEAN;
97 }
98
99 @Override
100 public char getChar()
101 {
102 return NONDEFAULT_CHAR;
103 }
104
105 @Override
106 public byte getByte()
107 {
108 return NONDEFAULT_BYTE;
109 }
110
111 @Override
112 public short getShort()
113 {
114 return NONDEFAULT_SHORT;
115 }
116
117 @Override
118 public int getInt()
119 {
120 return NONDEFAULT_INT;
121 }
122
123 @Override
124 public long getLong()
125 {
126 return NONDEFAULT_LONG;
127 }
128
129 @Override
130 public float getFloat()
131 {
132 return NONDEFAULT_FLOAT;
133 }
134
135 @Override
136 public double getDouble()
137 {
138 return NONDEFAULT_DOUBLE;
139 }
140
141 @Override
142 public String getString()
143 {
144 return NONDEFAULT_STRING;
145 }
146
147 @Override
148 public void operation()
149 {
150 ++operationCount;
151 }
152
153 @Override
154 public String concat(final String left, final String right)
155 {
156 return left + right;
157 }
158 }
159
160 private SampleJmxBridge sampleJmxBridge;
161 private MBeanServer platformMBeanServer;
162
163 @Before
164 public void setUp() throws Exception
165 {
166 sampleJmxBridge = new SampleJmxBridge();
167 platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
168 }
169
170 @Test
171 public void getObjectNameMentionsType()
172 {
173 final ObjectName objectName = sampleJmxBridge.getObjectName();
174 assertThat(objectName.toString(), containsString("Sample"));
175 }
176
177 @Test
178 public void notExposedToJmxBeforeRegister() throws Exception
179 {
180 final ObjectName objectName = sampleJmxBridge.getObjectName();
181 expectedException.expect(InstanceNotFoundException.class);
182 expectedException.expectMessage(objectName.toString());
183 platformMBeanServer.invoke(objectName, "operation", new Object[0], new String[0]);
184 }
185
186 @Test
187 public void registerExposesToJmx() throws Exception
188 {
189 final ObjectName objectName = sampleJmxBridge.getObjectName();
190 sampleJmxBridge.register();
191
192 final int before = sampleJmxBridge.getOperationCount();
193 platformMBeanServer.invoke(objectName, "operation", new Object[0], new String[0]);
194 assertThat(sampleJmxBridge.getOperationCount(), is(before + 1));
195 }
196
197 @Test
198 public void primitiveTypesAreReturnedBoxed() throws Exception
199 {
200
201
202 final ObjectName objectName = sampleJmxBridge.getObjectName();
203 sampleJmxBridge.register();
204
205 final Object aBoolean = platformMBeanServer.getAttribute(objectName, "Boolean");
206 assertThat(aBoolean, instanceOf(Boolean.class));
207 assertThat((Boolean) aBoolean, is(NONDEFAULT_BOOLEAN));
208
209 final Object aChar = platformMBeanServer.getAttribute(objectName, "Char");
210 assertThat(aChar, instanceOf(Character.class));
211 assertThat((Character) aChar, is(NONDEFAULT_CHAR));
212
213 final Object aByte = platformMBeanServer.getAttribute(objectName, "Byte");
214 assertThat(aByte, instanceOf(Byte.class));
215 assertThat((Byte) aByte, is(NONDEFAULT_BYTE));
216
217 final Object aShort = platformMBeanServer.getAttribute(objectName, "Short");
218 assertThat(aShort, instanceOf(Short.class));
219 assertThat((Short) aShort, is(NONDEFAULT_SHORT));
220
221 final Object anInt = platformMBeanServer.getAttribute(objectName, "Int");
222 assertThat(anInt, instanceOf(Integer.class));
223 assertThat((Integer) anInt, is(NONDEFAULT_INT));
224
225 final Object aLong = platformMBeanServer.getAttribute(objectName, "Long");
226 assertThat(aLong, instanceOf(Long.class));
227 assertThat((Long) aLong, is(NONDEFAULT_LONG));
228
229 final Object aFloat = platformMBeanServer.getAttribute(objectName, "Float");
230 assertThat(aFloat, instanceOf(Float.class));
231 assertThat((Float) aFloat, is(NONDEFAULT_FLOAT));
232
233 final Object aDouble = platformMBeanServer.getAttribute(objectName, "Double");
234 assertThat(aDouble, instanceOf(Double.class));
235 assertThat((Double) aDouble, is(NONDEFAULT_DOUBLE));
236
237 final Object aString = platformMBeanServer.getAttribute(objectName, "String");
238 assertThat(aString, instanceOf(String.class));
239 assertThat((String) aString, is(NONDEFAULT_STRING));
240 }
241
242 @Test
243 public void parametersArePassedCorrectly() throws Exception
244 {
245 final ObjectName objectName = sampleJmxBridge.getObjectName();
246 sampleJmxBridge.register();
247
248 final Object[] params = { "left", "right" };
249 final String[] signature = new String[] { String.class.getName(), String.class.getName() };
250 final Object result = platformMBeanServer.invoke(objectName, "concat", params, signature);
251 assertThat(result, instanceOf(String.class));
252 assertThat((String) result, is("leftright"));
253 }
254
255 @Test
256 public void notExposedToJmxAfterUnregister() throws Exception
257 {
258 final ObjectName objectName = sampleJmxBridge.getObjectName();
259 sampleJmxBridge.register();
260 sampleJmxBridge.unregister();
261
262 expectedException.expect(InstanceNotFoundException.class);
263 expectedException.expectMessage(objectName.toString());
264 platformMBeanServer.invoke(objectName, "operation", new Object[0], new String[0]);
265 }
266
267 @Test
268 public void throwsIllegalStateExceptionIfReferenceIsCleared() throws Exception
269 {
270
271 final ObjectName objectName = sampleJmxBridge.getObjectName();
272
273 final AbstractJmxBridge.WeakMXBeanInvocationHandler<SampleMXBean> invocationHandler = sampleJmxBridge.registerInternal();
274
275
276 final Object aString = platformMBeanServer.getAttribute(objectName, "String");
277 assertThat(aString, instanceOf(String.class));
278 assertThat((String) aString, is(NONDEFAULT_STRING));
279
280 invocationHandler.getImplementationReference().clear();
281
282 expectedException.expect(RuntimeMBeanException.class);
283 expectedException.expectCause(Matchers.<Throwable>instanceOf(IllegalStateException.class));
284 expectedException.expectMessage(objectName.toString());
285 platformMBeanServer.invoke(objectName, "operation", new Object[0], new String[0]);
286 }
287
288 @Test
289 public void usageAfterReferenceClearsCausesUnregister() throws Exception
290 {
291 final ObjectName objectName = sampleJmxBridge.getObjectName();
292 final AbstractJmxBridge.WeakMXBeanInvocationHandler<SampleMXBean> invocationHandler = sampleJmxBridge.registerInternal();
293 invocationHandler.getImplementationReference().clear();
294
295 try
296 {
297 platformMBeanServer.invoke(objectName, "operation", new Object[0], new String[0]);
298 }
299 catch(RuntimeMBeanException ermb)
300 {
301
302 }
303
304
305 expectedException.expect(InstanceNotFoundException.class);
306 expectedException.expectMessage(objectName.toString());
307 platformMBeanServer.invoke(objectName, "operation", new Object[0], new String[0]);
308 }
309 }