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