jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostProvider.java
changeset 38127 2ab00cd4556e
parent 38125 1ad0239b6e4a
parent 38126 c3706b502779
child 38128 22391eb0c22d
equal deleted inserted replaced
38125:1ad0239b6e4a 38127:2ab00cd4556e
     1 /*
       
     2  * Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.jvmstat.perfdata.monitor.protocol.rmi;
       
    27 
       
    28 import sun.jvmstat.monitor.*;
       
    29 import sun.jvmstat.monitor.event.*;
       
    30 import sun.jvmstat.monitor.remote.*;
       
    31 import sun.jvmstat.perfdata.monitor.*;
       
    32 import java.util.*;
       
    33 import java.net.*;
       
    34 import java.io.*;
       
    35 import java.rmi.*;
       
    36 import java.util.HashMap;
       
    37 
       
    38 /**
       
    39  * Concrete implementation of the MonitoredHost interface for the
       
    40  * <em>rmi</em> protocol of the HotSpot PerfData monitoring implementation.
       
    41  *
       
    42  * @author Brian Doherty
       
    43  * @since 1.5
       
    44  */
       
    45 public class MonitoredHostProvider extends MonitoredHost {
       
    46     private static final String serverName = "/JStatRemoteHost";
       
    47     private static final int DEFAULT_POLLING_INTERVAL = 1000;
       
    48 
       
    49     private ArrayList<HostListener> listeners;
       
    50     private NotifierTask task;
       
    51     private HashSet<Integer> activeVms;
       
    52     private RemoteVmManager vmManager;
       
    53     private RemoteHost remoteHost;
       
    54     private Timer timer;
       
    55 
       
    56     /**
       
    57      * Create a MonitoredHostProvider instance using the given HostIdentifier.
       
    58      *
       
    59      * @param hostId the host identifier for this MonitoredHost
       
    60      * @throws MonitorException Thrown on any error encountered while
       
    61      *                          communicating with the remote host.
       
    62      */
       
    63     public MonitoredHostProvider(HostIdentifier hostId)
       
    64            throws MonitorException {
       
    65         this.hostId = hostId;
       
    66         this.listeners = new ArrayList<HostListener>();
       
    67         this.interval = DEFAULT_POLLING_INTERVAL;
       
    68         this.activeVms = new HashSet<Integer>();
       
    69 
       
    70         String rmiName;
       
    71         String sn = serverName;
       
    72         String path = hostId.getPath();
       
    73 
       
    74         if ((path != null) && (path.length() > 0)) {
       
    75             sn = path;
       
    76         }
       
    77 
       
    78         if (hostId.getPort() != -1) {
       
    79             rmiName = "rmi://" + hostId.getHost() + ":" + hostId.getPort() + sn;
       
    80         } else {
       
    81             rmiName = "rmi://" + hostId.getHost() + sn;
       
    82         }
       
    83 
       
    84         try {
       
    85             remoteHost = (RemoteHost)Naming.lookup(rmiName);
       
    86 
       
    87         } catch (RemoteException e) {
       
    88             /*
       
    89              * rmi registry not available
       
    90              *
       
    91              * Access control exceptions, where the rmi server refuses a
       
    92              * connection based on policy file configuration, come through
       
    93              * here on the client side. Unfortunately, the RemoteException
       
    94              * doesn't contain enough information to determine the true cause
       
    95              * of the exception. So, we have to output a rather generic message.
       
    96              */
       
    97             String message = "RMI Registry not available at "
       
    98                              + hostId.getHost();
       
    99 
       
   100             if (hostId.getPort() == -1) {
       
   101                 message = message + ":"
       
   102                           + java.rmi.registry.Registry.REGISTRY_PORT;
       
   103             } else {
       
   104                 message = message + ":" + hostId.getPort();
       
   105             }
       
   106 
       
   107             if (e.getMessage() != null) {
       
   108                 throw new MonitorException(message + "\n" + e.getMessage(), e);
       
   109             } else {
       
   110                 throw new MonitorException(message, e);
       
   111             }
       
   112 
       
   113         } catch (NotBoundException e) {
       
   114             // no server with given name
       
   115             String message = e.getMessage();
       
   116             if (message == null) message = rmiName;
       
   117             throw new MonitorException("RMI Server " + message
       
   118                                        + " not available", e);
       
   119         } catch (MalformedURLException e) {
       
   120             // this is a programming problem
       
   121             e.printStackTrace();
       
   122             throw new IllegalArgumentException("Malformed URL: " + rmiName);
       
   123         }
       
   124         this.vmManager = new RemoteVmManager(remoteHost);
       
   125         this.timer = new Timer(true);
       
   126     }
       
   127 
       
   128     /**
       
   129      * {@inheritDoc}
       
   130      */
       
   131     public MonitoredVm getMonitoredVm(VmIdentifier vmid)
       
   132                        throws MonitorException {
       
   133         return getMonitoredVm(vmid, DEFAULT_POLLING_INTERVAL);
       
   134     }
       
   135 
       
   136     /**
       
   137      * {@inheritDoc}
       
   138      */
       
   139     public MonitoredVm getMonitoredVm(VmIdentifier vmid, int interval)
       
   140                        throws MonitorException {
       
   141         VmIdentifier nvmid = null;
       
   142         try {
       
   143             nvmid = hostId.resolve(vmid);
       
   144             RemoteVm rvm = remoteHost.attachVm(vmid.getLocalVmId(),
       
   145                                                vmid.getMode());
       
   146             RemoteMonitoredVm rmvm = new RemoteMonitoredVm(rvm, nvmid, timer,
       
   147                                                            interval);
       
   148             rmvm.attach();
       
   149             return rmvm;
       
   150 
       
   151         } catch (RemoteException e) {
       
   152             throw new MonitorException("Remote Exception attaching to "
       
   153                                        + nvmid.toString(), e);
       
   154         } catch (URISyntaxException e) {
       
   155             /*
       
   156              * the VmIdentifier is expected to be a valid and should resolve
       
   157              * easonably against the host identifier. A URISyntaxException
       
   158              * here is most likely a programming error.
       
   159              */
       
   160             throw new IllegalArgumentException("Malformed URI: "
       
   161                                                + vmid.toString(), e);
       
   162         }
       
   163     }
       
   164 
       
   165     /**
       
   166      * {@inheritDoc}
       
   167      */
       
   168     public void detach(MonitoredVm vm) throws MonitorException {
       
   169         RemoteMonitoredVm rmvm = (RemoteMonitoredVm)vm;
       
   170         rmvm.detach();
       
   171         try {
       
   172             remoteHost.detachVm(rmvm.getRemoteVm());
       
   173 
       
   174         } catch (RemoteException e) {
       
   175             throw new MonitorException("Remote Exception detaching from "
       
   176                                        + vm.getVmIdentifier().toString(), e);
       
   177         }
       
   178     }
       
   179 
       
   180     /**
       
   181      * {@inheritDoc}
       
   182      */
       
   183     public void addHostListener(HostListener listener) {
       
   184         synchronized(listeners) {
       
   185             listeners.add(listener);
       
   186             if (task == null) {
       
   187                 task = new NotifierTask();
       
   188                 timer.schedule(task, 0, interval);
       
   189             }
       
   190         }
       
   191     }
       
   192 
       
   193     /**
       
   194      * {@inheritDoc}
       
   195      */
       
   196     public void removeHostListener(HostListener listener) {
       
   197         /*
       
   198          * XXX: if a disconnect method is added, make sure it calls
       
   199          * this method to unregister this object from the watcher. otherwise,
       
   200          * an unused MonitoredHostProvider instance may go uncollected.
       
   201          */
       
   202         synchronized(listeners) {
       
   203             listeners.remove(listener);
       
   204             if (listeners.isEmpty() && (task != null)) {
       
   205                 task.cancel();
       
   206                 task = null;
       
   207             }
       
   208         }
       
   209     }
       
   210 
       
   211     public void setInterval(int newInterval) {
       
   212         synchronized(listeners) {
       
   213             if (newInterval == interval) {
       
   214                 return;
       
   215             }
       
   216 
       
   217             int oldInterval = interval;
       
   218             super.setInterval(newInterval);
       
   219 
       
   220             if (task != null) {
       
   221                 task.cancel();
       
   222                 NotifierTask oldTask = task;
       
   223                 task = new NotifierTask();
       
   224                 CountedTimerTaskUtils.reschedule(timer, oldTask, task,
       
   225                                                  oldInterval, newInterval);
       
   226             }
       
   227         }
       
   228     }
       
   229 
       
   230     /**
       
   231      * {@inheritDoc}
       
   232      */
       
   233     public Set<Integer> activeVms() throws MonitorException {
       
   234         return vmManager.activeVms();
       
   235     }
       
   236 
       
   237     /**
       
   238      * Fire VmStatusChangeEvent events to HostListener objects
       
   239      *
       
   240      * @param active Set of Integer objects containing the local
       
   241      *               Vm Identifiers of the active JVMs
       
   242      * @param started Set of Integer objects containing the local
       
   243      *                Vm Identifiers of new JVMs started since last
       
   244      *                interval.
       
   245      * @param terminated Set of Integer objects containing the local
       
   246      *                   Vm Identifiers of terminated JVMs since last
       
   247      *                   interval.
       
   248      */
       
   249     @SuppressWarnings("unchecked") // Cast of result of clone
       
   250     private void fireVmStatusChangedEvents(Set<Integer> active, Set<Integer> started,
       
   251                                            Set<Integer> terminated) {
       
   252         ArrayList<HostListener> registered = null;
       
   253         VmStatusChangeEvent ev = null;
       
   254 
       
   255         synchronized(listeners) {
       
   256             registered = (ArrayList)listeners.clone();
       
   257         }
       
   258 
       
   259         for (Iterator<HostListener> i = registered.iterator(); i.hasNext(); /* empty */) {
       
   260             HostListener l = i.next();
       
   261             if (ev == null) {
       
   262                 ev = new VmStatusChangeEvent(this, active, started, terminated);
       
   263             }
       
   264             l.vmStatusChanged(ev);
       
   265         }
       
   266     }
       
   267 
       
   268     /**
       
   269      * Fire hostDisconnectEvent events.
       
   270      */
       
   271     @SuppressWarnings("unchecked") // Cast of result of clone
       
   272     void fireDisconnectedEvents() {
       
   273         ArrayList<HostListener> registered = null;
       
   274         HostEvent ev = null;
       
   275 
       
   276         synchronized(listeners) {
       
   277             registered = (ArrayList)listeners.clone();
       
   278         }
       
   279 
       
   280         for (Iterator<HostListener> i = registered.iterator(); i.hasNext(); /* empty */) {
       
   281             HostListener l = i.next();
       
   282             if (ev == null) {
       
   283                 ev = new HostEvent(this);
       
   284             }
       
   285             l.disconnected(ev);
       
   286         }
       
   287     }
       
   288 
       
   289     /**
       
   290      * class to poll the remote machine and generate local event notifications.
       
   291      */
       
   292     private class NotifierTask extends CountedTimerTask {
       
   293         public void run() {
       
   294             super.run();
       
   295 
       
   296             // save the last set of active JVMs
       
   297             Set<Integer> lastActiveVms = activeVms;
       
   298 
       
   299             try {
       
   300                 // get the current set of active JVMs
       
   301                 activeVms = (HashSet<Integer>)vmManager.activeVms();
       
   302 
       
   303             } catch (MonitorException e) {
       
   304                 // XXX: use logging api
       
   305                 System.err.println("MonitoredHostProvider: polling task "
       
   306                                    + "caught MonitorException:");
       
   307                 e.printStackTrace();
       
   308 
       
   309                 // mark the HostManager as errored and notify listeners
       
   310                 setLastException(e);
       
   311                 fireDisconnectedEvents();
       
   312             }
       
   313 
       
   314             if (activeVms.isEmpty()) {
       
   315                 return;
       
   316             }
       
   317 
       
   318             Set<Integer> startedVms = new HashSet<>();
       
   319             Set<Integer> terminatedVms = new HashSet<>();
       
   320 
       
   321             for (Iterator<Integer> i = activeVms.iterator(); i.hasNext(); /* empty */ ) {
       
   322                 Integer vmid = i.next();
       
   323                 if (!lastActiveVms.contains(vmid)) {
       
   324                     // a new file has been detected, add to set
       
   325                     startedVms.add(vmid);
       
   326                 }
       
   327             }
       
   328 
       
   329             for (Iterator<Integer> i = lastActiveVms.iterator(); i.hasNext();
       
   330                     /* empty */ ) {
       
   331                 Integer o = i.next();
       
   332                 if (!activeVms.contains(o)) {
       
   333                     // JVM has terminated, remove it from the active list
       
   334                     terminatedVms.add(o);
       
   335                 }
       
   336             }
       
   337 
       
   338             if (!startedVms.isEmpty() || !terminatedVms.isEmpty()) {
       
   339                 fireVmStatusChangedEvents(activeVms, startedVms, terminatedVms);
       
   340             }
       
   341         }
       
   342     }
       
   343 }