Home | History | Annotate | Download | only in scandir
      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