1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * 
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * The contents of this file are subject to the terms of either the Universal Permissive License
   7  * v 1.0 as shown at http://oss.oracle.com/licenses/upl
   8  *
   9  * or the following license:
  10  *
  11  * Redistribution and use in source and binary forms, with or without modification, are permitted
  12  * provided that the following conditions are met:
  13  * 
  14  * 1. Redistributions of source code must retain the above copyright notice, this list of conditions
  15  * and the following disclaimer.
  16  * 
  17  * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
  18  * conditions and the following disclaimer in the documentation and/or other materials provided with
  19  * the distribution.
  20  * 
  21  * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
  22  * endorse or promote products derived from this software without specific prior written permission.
  23  * 
  24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  26  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  27  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
  31  * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  */
  33 package org.openjdk.jmc.rjmx.test.synthetic;
  34 
  35 import static org.junit.Assert.assertNotNull;
  36 import static org.junit.Assert.assertTrue;
  37 
  38 import java.io.IOException;
  39 
  40 import javax.management.InstanceNotFoundException;
  41 import javax.management.IntrospectionException;
  42 import javax.management.ListenerNotFoundException;
  43 import javax.management.MBeanInfo;
  44 import javax.management.MBeanNotificationInfo;
  45 import javax.management.MBeanServerConnection;
  46 import javax.management.MalformedObjectNameException;
  47 import javax.management.Notification;
  48 import javax.management.NotificationListener;
  49 import javax.management.ObjectName;
  50 import javax.management.ReflectionException;
  51 
  52 import org.junit.Assume;
  53 import org.junit.Before;
  54 import org.junit.Test;
  55 
  56 import org.openjdk.jmc.rjmx.IConnectionHandle;
  57 import org.openjdk.jmc.rjmx.test.ServerHandleTestCase;
  58 
  59 public class SyntheticNotificationTest extends ServerHandleTestCase {
  60 
  61         private IConnectionHandle handle;
  62         private MBeanServerConnection connection;
  63         private volatile boolean gotNotification = false;
  64 
  65         private class SyntheticNotificationListener implements NotificationListener {
  66                 private Notification lastNotification;
  67 
  68                 @Override
  69                 public void handleNotification(Notification notification, Object handback) {
  70                         lastNotification = notification;
  71                         gotNotification = true;
  72                         synchronized (SyntheticNotificationTest.this) {
  73                                 SyntheticNotificationTest.this.notify();
  74                         }
  75                 }
  76 
  77                 public Notification getLastNotification() {
  78                         return lastNotification;
  79                 }
  80         }
  81 
  82         @Override
  83         @Before
  84         public void setUp() throws Exception {
  85                 super.setUp();
  86                 handle = getDefaultServer().connect("Test"); //$NON-NLS-1$
  87                 connection = handle.getServiceOrThrow(MBeanServerConnection.class);
  88                 gotNotification = false;
  89         }
  90 
  91         @Override
  92         public void tearDown() throws Exception {
  93                 handle.close();
  94         }
  95 
  96         /**
  97          * Tests that we can add synthetic notifications.
  98          */
  99         @Test
 100         public void testGetNotificationMetadata() throws InstanceNotFoundException, IntrospectionException,
 101                         MalformedObjectNameException, ReflectionException, NullPointerException, IOException {
 102                 MBeanInfo info = connection.getMBeanInfo(new ObjectName("org.openjdk.jmc.test:type=Test")); //$NON-NLS-1$
 103                 assertTrue(info.getNotifications().length > 0);
 104         }
 105 
 106         /**
 107          * Tests that we can have attributes AND notifications on the same synthetic.
 108          */
 109         @Test
 110         public void testCombinedMetadata() throws InstanceNotFoundException, IntrospectionException,
 111                         MalformedObjectNameException, ReflectionException, NullPointerException, IOException {
 112                 MBeanInfo info = connection.getMBeanInfo(new ObjectName("org.openjdk.jmc.test:type=Test")); //$NON-NLS-1$
 113                 assertTrue(info.getNotifications().length > 0);
 114                 assertTrue(info.getAttributes().length > 0);
 115         }
 116 
 117         /**
 118          * Tests that we can overload existing real MBean with notification and still get values.
 119          */
 120         @Test
 121         public void testOverloadMetadata() throws InstanceNotFoundException, IntrospectionException,
 122                         MalformedObjectNameException, ReflectionException, NullPointerException, IOException {
 123                 MBeanInfo info = connection.getMBeanInfo(new ObjectName("java.lang:type=ClassLoading")); //$NON-NLS-1$
 124                 assertTrue(info.getNotifications().length > 0);
 125                 assertTrue(info.getAttributes().length > 0);
 126         }
 127 
 128         /**
 129          * Tests that we can shadow an existing notification.
 130          */
 131         @Test
 132         public void testShadowMetadata() throws InstanceNotFoundException, IntrospectionException,
 133                         MalformedObjectNameException, ReflectionException, NullPointerException, IOException {
 134                 Assume.assumeTrue("FIXME: Shadowing does not work yet!", false); //$NON-NLS-1$
 135                 MBeanInfo info = connection.getMBeanInfo(new ObjectName("java.lang:type=Memory")); //$NON-NLS-1$
 136                 assertTrue(info.getNotifications().length > 0);
 137                 for (MBeanNotificationInfo notificationInfo : info.getNotifications()) {
 138                         if (notificationInfo.getName().equals("java.management.memory.collection.threshold.exceeded")) { //$NON-NLS-1$
 139                                 assertTrue("Failed to shadow description", notificationInfo.getDescription().contains("shadow")); //$NON-NLS-1$ //$NON-NLS-2$
 140                                 assertTrue("Got the wrong type:" + notificationInfo.getNotifTypes()[0], "int".equals(notificationInfo //$NON-NLS-1$ //$NON-NLS-2$
 141                                                 .getNotifTypes()[0]));
 142                         } else {
 143                                 assertTrue("Should NOT contain shadow!", !notificationInfo.getDescription().contains("shadow")); //$NON-NLS-1$ //$NON-NLS-2$
 144                                 assertTrue("Should not be int!", !"int".equals(notificationInfo.getNotifTypes()[0])); //$NON-NLS-1$ //$NON-NLS-2$
 145                         }
 146                 }
 147         }
 148 
 149         @Test
 150         public void testNotificationListener() throws InstanceNotFoundException, MalformedObjectNameException,
 151                         NullPointerException, IOException, InterruptedException, ListenerNotFoundException {
 152                 Notification notif = null;
 153                 SyntheticNotificationListener listener = new SyntheticNotificationListener();
 154                 ObjectName testMBean = new ObjectName("org.openjdk.jmc.test:type=Test"); //$NON-NLS-1$
 155                 connection.addNotificationListener(testMBean, listener, null, null);
 156                 synchronized (this) {
 157                         this.wait(30000);
 158                         notif = listener.getLastNotification();
 159                 }
 160                 assertTrue("Never got any notification!", gotNotification); //$NON-NLS-1$
 161                 assertNotNull(notif);
 162                 assertTrue("Expected a user data > 0!", ((Integer) notif.getUserData()) > 0); //$NON-NLS-1$
 163                 assertTrue("Expected Woho!", notif.getMessage().startsWith("Woho!")); //$NON-NLS-1$ //$NON-NLS-2$
 164                 connection.removeNotificationListener(testMBean, listener, null, null);
 165         }
 166 }