All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ebay.jetstream.management.Management Maven / Gradle / Ivy

/*******************************************************************************
 *  Copyright © 2012-2015 eBay Software Foundation
 *  This program is dual licensed under the MIT and Apache 2.0 licenses.
 *  Please see LICENSE for more information.
 *******************************************************************************/
/**
 *
 */
package com.ebay.jetstream.management;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.jmx.export.annotation.ManagedResource;

import com.ebay.jetstream.util.CommonUtils;

/**
 * 
 * 
 */
public class Management {
  public static class BeanFolder extends ConcurrentHashMap {
    private static final long serialVersionUID = 1L;

    protected BeanFolder() {
    }
  }

  private static Map> s_resourceFormatters = new HashMap>();
  private static List s_listeners = new ArrayList();
  private static final String PATH_SEPARATOR = "/";
  private static final String PATH_RELATIVE = "./";
  private static BeanFolder s_directory = new BeanFolder();

  /**
   * Adds a managed bean to the directory. The full path of the bean is taken from the ManagedResource annotation for
   * the bean.
   * 
   * @param bean
   *            the bean to manage.
   * @return the path to the bean.
   */
  public static String addBean(Object bean) {
    return addBean(null, bean);
  }

  /**
   * Adds a managed bean to the directory. Missing path nodes are created as necessary. An IllegalArgumentException is
   * thrown if the path is illegal. The path given is combined with any path from a ManagedResource annotation. If the
   * annotation has an objectName prefixed with "./", the annotated path is added to the end of the given path, else it
   * is added to the beginning of the given path.
   * 
   * @param path
   *            the path to the managed bean, separated by '/' characters, with the bean name at the path end, or null.
   *            If null, the path is taken completely from the ManagedResource annotation for the bean.
   * 
   * @param bean
   *            the bean to manage.
   * 
   * @return the path to the bean.
   * 
   * @throws IllegalArgumentException
   *             if the path already exists or includes a non-leaf managed bean.
   */
  public static String addBean(String path, Object bean) {
    String rpath = getResourcePath(path, bean);
    String[] pc = rpath.split(PATH_SEPARATOR);
    Object object = getPath(pc, 1);
    if (!(object instanceof BeanFolder))
      throw new IllegalArgumentException("bean already exists at " + rpath);
    ((BeanFolder) object).put(pc[pc.length - 1], bean);
    notifyListeners(bean, rpath, ManagementListener.BeanAddedEvent.class);
    return rpath;
  }

  /**
   * Gets a managed bean or bean folder. An exception is thrown if the path is illegal or does not exist.
   * 
   * @param path
   *            the path to the Bean or BeanFolder.
   * 
   * @return the Bean or BeanFolder described by the given path.
   */
  public static Object getBeanOrFolder(String path) {
    return CommonUtils.isEmptyTrimmed(path) ? s_directory : getPath(path.split(PATH_SEPARATOR), 0);
  }

  public static List getManagementListeners() {
    return Collections.unmodifiableList(s_listeners);
  }

  /**
   * Gets a new instance of a ManagedResourceFormatter for the given format.
   * 
   * @param format
   *            the string format name.
   * 
   * @return the instance of ManagedResourceFormatter for the given format.
   * 
   * @throws InstantiationException
   * @throws IllegalAccessException
   */
  public static ManagedResourceFormatter getResourceFormatter(String format) throws InstantiationException,
      IllegalAccessException {
    Class clazz = s_resourceFormatters.get(format);
    return clazz == null ? null : clazz.newInstance();
  }

  public static Set getResourceFormatters() {
    return s_resourceFormatters.keySet();
  }

  public static void registerManagementListener(ManagementListener listener) {
    s_listeners.add(listener);
  }

  /**
   * Registers a ManagedResourceFormatter to a format name.
   * 
   * @param format
   *            the string format name to register for.
   * @param formatterClass
   *            the resource formatter class that implements ManagedResourceFormatter. The class must define a default
   *            (no parameters) constructor.
   */
  public static void registerResourceFormatter(String format, Class formatterClass) {
    s_resourceFormatters.put(format, formatterClass);
  }

  /**
   * Removes a bean or tree from the directory.
   * 
   * @param path
   *            the path to a bean or BeanFolder
   * @return true iff anything was removed
   */
  public static boolean removeBeanOrFolder(String path) {
    return removePath(path.split(PATH_SEPARATOR), s_directory, 0) > 0;
  }

  /**
   * Removes a bean or tree from the directory.
   * 
   * @param path
   *            the path to a bean or folder, or null. If null, the full path to the bean is calculated from the
   *            ManagedResource annotation for the bean.
   * @param bean
   *            the bean to remove
   * @return true iff anything was removed
   */
  public static boolean removeBeanOrFolder(String path, Object bean) {
    return removeBeanOrFolder(getResourcePath(path, bean));
  }

  private static String checkLevel(String pathLevel) {
    if (pathLevel == null || pathLevel.length() == 0)
      throw new IllegalArgumentException("empty path level found");
    return pathLevel;
  }

  /**
   * Gets the path to BeanFolder or managed bean, and optionally adds missing path components to the directory.
   * 
   * @param path
   *            the path to the managed bean, including the managed bean name.
   * @param mode
   *            N <= 0: no add and limit traversal to Nth from end; N > 0: add to the folder to Nth from end.
   * @return the target of the path if found, or the containing folder (mode = 1).
   * @throws IllegalArgumentException
   *             if the path has a managed bean that is not at the path end, or if part of the path is missing (mode ==
   *             -1).
   */
  private static Object getPath(String[] path, int mode) {
    BeanFolder folder = s_directory;
    Object object = null;
    // traverse the path
    int istart = 0;
    for (int limit = path.length - (mode > 0 ? 0 : mode); istart < limit; istart++) {
      object = folder.get(checkLevel(path[istart]));
      if (object instanceof BeanFolder)
        // this level is a folder, go to next (or end)
        folder = (BeanFolder) object;
      else if (object == null) {
        if (mode <= 0)
          // missing a level
          throw new IllegalArgumentException("no beans exist at " + path[istart]);
        else {
          // mode > 0, create missing levels
          for (object = folder, limit = path.length - mode; istart < limit; istart++) {
            folder = (BeanFolder) object;
            folder.put(checkLevel(path[istart]), object = new BeanFolder());
          }
          break;
        }
      }
      // object not a folder, and not null
      else if (istart != path.length - 1)
        // found a bean in the middle of the path
        throw new IllegalArgumentException("expecting BeanFolder, found managed bean at " + path[istart]);
    }
    return object;
  }

  private static String getResourcePath(String path, Object bean) {
    String rpath = path;
    ManagedResource mr = bean.getClass().getAnnotation(ManagedResource.class);
    if (mr != null) {
      String xpath = mr.objectName();
      if (xpath == null || xpath.length() == 0)
        xpath = mr.value();
      if (xpath != null && xpath.length() > 0) {
        rpath = path == null ? "" : xpath.startsWith(PATH_RELATIVE) ? path + PATH_SEPARATOR : PATH_SEPARATOR + path;
        rpath = xpath.startsWith(PATH_RELATIVE) ? rpath + xpath.substring(PATH_RELATIVE.length()) : xpath + rpath;
      }
    }
    return rpath;
  }

  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="REC_CATCH_EXCEPTION", justification="Want to suprress exceptions here.")
  private static void notifyListeners(Object bean, String path,
      Class eventClass) {
    if (!s_listeners.isEmpty()) {
      ManagementListener.BeanChangedEvent event = null;
      try {
        event = eventClass.getConstructor(Object.class, String.class).newInstance(bean, path);
        for (ManagementListener listener : s_listeners)
          try {
            listener.beanChanged(event);
          }
          catch (Exception e) {
          }
      }
      catch (Exception e) {
      }
    }
  }

  private static int removePath(String[] path, BeanFolder folder, int index) {
    String s = checkLevel(path[index]);
    Object object = folder.get(s);
    int result = 0;
    // recurse to sub-folders
    if (object instanceof BeanFolder && index < path.length - 1) {
      result = removePath(path, (BeanFolder) object, index + 1);
    }
    // remove path leaf and folders above that becomes empty due to this
    if (object != null && (result == path.length - index && folder.size() == 1 || index == path.length - 1)) {
      folder.remove(s);
      if (result++ == 0)
        notifyListeners(object, s, ManagementListener.BeanRemovedEvent.class);
    }
    return result;
  }

  private Management() {
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy