FwdClientJMX.java

/*
** Module   : FwdClientJMX.java
** Abstract : FWD JMX instrumentation. 
**
** Copyright (c) 2024, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
** 001 HC  20240222 Created initial version.
*/

/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
** 
** Additional terms under GNU Affero GPL version 3 section 7:
** 
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
**   terms apply to the works covered under the License.  These additional terms
**   are non-permissive additional terms allowed under Section 7 of the GNU
**   Affero GPL version 3 and may not be removed by you.
** 
**   0. Attribution Requirement.
** 
**     You must preserve all legal notices or author attributions in the covered
**     work or Appropriate Legal Notices displayed by works containing the covered
**     work.  You may not remove from the covered work any author or developer
**     credit already included within the covered work.
** 
**   1. No License To Use Trademarks.
** 
**     This license does not grant any license or rights to use the trademarks
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
**     of Golden Code Development Corporation. You are not authorized to use the
**     name Golden Code, FWD, or the names of any author or contributor, for
**     publicity purposes without written authorization.
** 
**   2. No Misrepresentation of Affiliation.
** 
**     You may not represent yourself as Golden Code Development Corporation or FWD.
** 
**     You may not represent yourself for publicity purposes as associated with
**     Golden Code Development Corporation, FWD, or any author or contributor to
**     the covered work, without written authorization.
** 
**   3. No Misrepresentation of Source or Origin.
** 
**     You may not represent the covered work as solely your work.  All modified
**     versions of the covered work must be marked in a reasonable way to make it
**     clear that the modified work is not originating from Golden Code Development
**     Corporation or FWD.  All modified versions must contain the notices of
**     attribution required in this license.
*/

package com.goldencode.p2j.jmx;

import com.goldencode.p2j.util.logging.*;
import com.goldencode.util.*;

import javax.management.*;
import java.io.*;
import java.lang.management.*;
import java.util.*;
import java.util.logging.*;

/** FWD JMX instrumentation */
public class FwdClientJMX
extends FwdJMX
{
   /** Logger. */
   private static final CentralLogger LOG = CentralLogger.get(FwdClientJMX.class.getName());

   /**
    * Default constructor
    */
   private FwdClientJMX()
   {
      super("FWD Client");
   }

   /**
    * Register MBeans
    */
   public void registerMBeans()
   {
      try
      {
         MBeanServer server = ManagementFactory.getPlatformMBeanServer();
         for (MapCounter c: MapCounter.values())
         {
            server.registerMBean(c.getCounter(), new ObjectName("com.goldencode.p2j:name=" + c.name()));
         }
         server.registerMBean(this,
               new ObjectName("com.goldencode.p2j:name=All"));
      } 
      catch (Exception e)
      {
         LOG.log(Level.SEVERE, "MBean registration failed", e);
      }
   }

   /**
    * Initialize singleton
    */
   public static void init()
   {
      Holder.INSTANCE.registerMBeans();
   }
   
   /**
    * Register MBean
    * 
    * @param mbean
    *        MBean to be registered 
    * @param name
    *        MBean name 
    */
   public static void register(Object mbean, String name)
   {
      Holder.INSTANCE.registerMBean(mbean, name);
   }

   /**
    * Instance holder (Lazy initialization)
    */
   private static class Holder
   {
      static final FwdClientJMX INSTANCE = new FwdClientJMX();
   }

   /**
    * String-long map counter
    */
   public static enum MapCounter
   implements OptionalMapCounter
   {
      /** Spreadsheet command invocation nano times */
      SpreadsheetCmdNanos,

      /** Spreadsheet server event handler invocation nano times */
      COMEventNanos;

      /** Counter instance */
      private final SimpleMapCounter counter = new SimpleMapCounter();

      /**
       * Register enable/disable setter
       * @param agent
       *        enable/disable setter
       */
      @Override
      public void register(BooleanConsumer agent)
      {
         counter.register(agent);
      }

      /**
       * Update counter
       *
       * @param valueName
       *        value name to update
       * @param value
       *        new value
       */
      @Override
      public void update(String valueName, long value)
      {
         counter.update(valueName, value);
      }

      /**
       * Return the string representation of the counter
       * 
       * @param    ts
       *           The measurement time stamp
       * @param    comment
       *           The comment
       * 
       * @return   The string representation of the counter
       * 
       * @throws   IOException
       *           If IO exception occurs
       */
      public String toString(String ts, String comment) throws IOException
      {
         return counter.toString();
      }

      /**
       * Return counter instance
       * @return counter instance
       */
      public SimpleMapCounter getCounter()
      {
         return counter;
      }
   }

   /**
    * Print all counters' values to the file.
    *
    * @param   file 
    *          The output file name (will be appended if exists).
    *
    * @throws  IOException 
    *          If IO exception occurs
    */
   @Override
   public synchronized void dumpAll(String file) throws IOException
   {
      String annotation = getAnnotation();

      for(MapCounter c: MapCounter.values())
      {
         c.getCounter().print(annotation + ":" + c.name(), file);
      }
   }
   
   /** Reset all counters */
   @Override
   public synchronized void resetAll()
   {
      Arrays.stream(MapCounter.values()).map(MapCounter::getCounter).forEach(SimpleLongCounter::reset);
   }
   
   /**
    * Enable/disable all counters
    * @param val
    *        new value of the "enable" flag
    */
   @Override
   public synchronized void enableAll(boolean val)
   {
      Arrays.stream(MapCounter.values()).map(MapCounter::getCounter).forEach(c -> c.enable(val));
   }
}