1 /* 2 * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This source code is provided to illustrate the usage of a given feature 34 * or technique and has been deliberately simplified. Additional steps 35 * required for a production-quality application, such as security checks, 36 * input validation and proper error handling, might not be present in 37 * this sample code. 38 */ 39 40 41 package com.sun.jmx.examples.scandir; 42 43 import com.sun.jmx.examples.scandir.ScanManagerMXBean.ScanState; 44 import java.io.IOException; 45 import java.lang.management.ManagementFactory; 46 import java.util.concurrent.BlockingQueue; 47 import java.util.concurrent.LinkedBlockingQueue; 48 import java.util.concurrent.TimeUnit; 49 import java.util.logging.Logger; 50 import javax.management.JMException; 51 import javax.management.Notification; 52 import javax.management.NotificationEmitter; 53 import javax.management.NotificationListener; 54 55 /** 56 * <p> 57 * The <code>ScanDirAgent</code> is the Agent class for the <i>scandir</i> 58 * application. 59 * This class contains the {@link #main} method to start a standalone 60 * <i>scandir</i> application. 61 * </p> 62 * <p> 63 * The {@link #main main()} method simply registers a {@link 64 * ScanManagerMXBean} in the platform MBeanServer - see {@link #init init}, 65 * and then waits for someone to call {@link ScanManagerMXBean#close close} 66 * on that MBean. 67 * </p> 68 * <p> 69 * When the {@link ScanManagerMXBean} state is switched to {@link 70 * ScanManagerMXBean.ScanState#CLOSED CLOSED}, {@link #cleanup cleanup} is 71 * called, the {@link ScanManagerMXBean} is unregistered, and the application 72 * terminates (i.e. the main thread completes). 73 * </p> 74 * @author Sun Microsystems, 2006 - All rights reserved. 75 **/ 76 public class ScanDirAgent { 77 78 /** 79 * A logger for this class. 80 **/ 81 private static final Logger LOG = 82 Logger.getLogger(ScanDirAgent.class.getName()); 83 84 // Proxy to the ScanManagerMXBean - created by init(); 85 // 86 private volatile ScanManagerMXBean proxy = null; 87 88 // A queue to put received Notifications. 89 // 90 private final BlockingQueue<Notification> queue; 91 92 // A listener that will put notifications into the queue. 93 // 94 private final NotificationListener listener; 95 96 /** 97 * Creates a new instance of ScanDirAgent 98 * You will need to call {@link #init()} later on in order to initialize 99 * the application. 100 * @see #main 101 **/ 102 public ScanDirAgent() { 103 // Initialize the notification queue 104 queue = new LinkedBlockingQueue<Notification>(); 105 106 // Creates the listener. 107 listener = new NotificationListener() { 108 public void handleNotification(Notification notification, 109 Object handback) { 110 try { 111 // Just put the received notification in the queue. 112 // It will be consumed later on by 'waitForClose()' 113 // 114 LOG.finer("Queuing received notification "+notification); 115 queue.put(notification); 116 } catch (InterruptedException ex) { 117 // OK 118 } 119 } 120 }; 121 } 122 123 /** 124 * Initialize the application by registering a ScanManagerMXBean in 125 * the platform MBeanServer 126 * @throws java.io.IOException Registration failed for communication-related reasons. 127 * @throws javax.management.JMException Registration failed for JMX-related reasons. 128 */ 129 public void init() throws IOException, JMException { 130 131 // Registers the ScanManagerMXBean singleton in the 132 // platform MBeanServer 133 // 134 proxy = ScanManager.register(); 135 136 // Registers a NotificationListener with the ScanManagerMXBean in 137 // order to receive state changed notifications. 138 // 139 ((NotificationEmitter)proxy).addNotificationListener(listener,null,null); 140 } 141 142 /** 143 * Cleanup after close: unregister the ScanManagerMXBean singleton. 144 * @throws java.io.IOException Cleanup failed for communication-related reasons. 145 * @throws javax.management.JMException Cleanup failed for JMX-related reasons. 146 */ 147 public void cleanup() throws IOException, JMException { 148 try { 149 ((NotificationEmitter)proxy). 150 removeNotificationListener(listener,null,null); 151 } finally { 152 ManagementFactory.getPlatformMBeanServer(). 153 unregisterMBean(ScanManager.SCAN_MANAGER_NAME); 154 } 155 } 156 157 /** 158 * Wait for someone to call 'close()' on the ScanManagerMXBean singleton. 159 * Every time its state changes, the ScanManagerMXBean emits a notification. 160 * We don't rely on the notification content (if we were using a remote 161 * connection, we could miss some notifications) - we simply use the 162 * state change notifications to react more quickly to state changes. 163 * We do so simply by polling the {@link BlockingQueue} in which our 164 * listener is pushing notifications, and checking the ScanManagerMXBean 165 * state every time that a notification is received. 166 * <p> 167 * We can do so because we know that once the ScanManagerMXBean state is 168 * switched to 'CLOSED', it will remain 'CLOSED' whatsoever. <br> 169 * Therefore we don't need to concern ourselves with the possibility of 170 * missing the window in which the ScanManagerMXBean state's will be 171 * CLOSED, because that particular window stays opened forever. 172 * <p> 173 * Had we wanted to wait for 'RUNNING', we would have needed to apply 174 * a different strategy - e.g. by taking into account the actual content 175 * of the state changed notifications we received. 176 * @throws java.io.IOException wait failed - a communication problem occurred. 177 * @throws javax.management.JMException wait failed - the MBeanServer threw an exception. 178 */ 179 public void waitForClose() throws IOException, JMException { 180 181 // Wait until state is closed 182 while(proxy.getState() != ScanState.CLOSED ) { 183 try { 184 // Wake up at least every 30 seconds - if we missed a 185 // notification - we will at least get a chance to 186 // call getState(). 30 seconds is obviously quite 187 // arbitrary - if this were a real daemon - id'be tempted 188 // to wait 30 minutes - knowing that any incoming 189 // notification will wake me up anyway. 190 // Note: we simply use the state change notifications to 191 // react more quickly to state changes: see javadoc above. 192 // 193 queue.poll(30,TimeUnit.SECONDS); 194 } catch (InterruptedException ex) { 195 // OK 196 } 197 } 198 } 199 200 /** 201 * The agent's main: {@link #init registers} a {@link ScanManagerMXBean}, 202 * {@link #waitForClose waits} until its state is {@link 203 * ScanManagerMXBean.ScanState#CLOSED CLOSED}, {@link #cleanup cleanup} 204 * and exits. 205 * @param args the command line arguments - ignored 206 * @throws java.io.IOException A communication problem occurred. 207 * @throws javax.management.JMException A JMX problem occurred. 208 */ 209 public static void main(String[] args) 210 throws IOException, JMException { 211 System.out.println("Initializing ScanManager..."); 212 final ScanDirAgent agent = new ScanDirAgent(); 213 agent.init(); 214 try { 215 System.out.println("Waiting for ScanManager to close..."); 216 agent.waitForClose(); 217 } finally { 218 System.out.println("Cleaning up..."); 219 agent.cleanup(); 220 } 221 } 222 } 223