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