/** Setup renderer hints. */
  public static void init() {
    if (initialized.getAndSet(true)) return;

    final Function<Double, Long> longValue =
        new Function<Double, Long>() {
          @Override
          public Long apply(@Nullable Double input) {
            if (input == null) return null;
            return input.longValue();
          }
        };

    RendererHints.register(UPTIME, RendererHints.displayValue(Time.toTimeStringRounded()));

    RendererHints.register(CPU_USAGE, RendererHints.displayValue(MathFunctions.percent(2)));
    RendererHints.register(AVERAGE_CPU_USAGE, RendererHints.displayValue(MathFunctions.percent(2)));

    RendererHints.register(
        FREE_MEMORY,
        RendererHints.displayValue(
            Functionals.chain(MathFunctions.times(1000L), ByteSizeStrings.metric())));
    RendererHints.register(
        TOTAL_MEMORY,
        RendererHints.displayValue(
            Functionals.chain(MathFunctions.times(1000L), ByteSizeStrings.metric())));
    RendererHints.register(
        USED_MEMORY,
        RendererHints.displayValue(
            Functionals.chain(MathFunctions.times(1000L), ByteSizeStrings.metric())));
    RendererHints.register(
        USED_MEMORY_DELTA_PER_SECOND_LAST,
        RendererHints.displayValue(Functionals.chain(longValue, ByteSizeStrings.metric())));
    RendererHints.register(
        USED_MEMORY_DELTA_PER_SECOND_IN_WINDOW,
        RendererHints.displayValue(Functionals.chain(longValue, ByteSizeStrings.metric())));
  }
 /** @deprecated Since 0.7.0. Use {@link brooklyn.util.math.MathFunctions#times(double)} instead */
 @Deprecated
 public static Function<Number, Double> times(final double x) {
   return MathFunctions.times(x);
 }
 /**
  * @param entity The entity at which to poll
  * @param jmxPollPeriod How often to poll
  * @return A {@link JmxFeed.Builder} configured to poll many interesting MXBeans at the given
  *     entity and to repeat according to the given poll period.
  *     <p>If an entity does not have MXBean stats enabled (i.e. {@link
  *     UsesJavaMXBeans#MXBEAN_STATS_ENABLED} is configured to false) then returns a builder
  *     configured with entity and duration but no polls.
  *     <p>Use {@link #connectMXBeanSensors(EntityLocal, Duration)} to create and build in one
  *     step.
  */
 @Nonnull
 @SuppressWarnings({"unchecked"})
 public static JmxFeed.Builder getMxBeanSensorsBuilder(
     EntityLocal entity, Duration jmxPollPeriod) {
   JmxFeed.Builder builder = JmxFeed.builder().entity(entity).period(jmxPollPeriod);
   if (isEntityMxBeanStatsEnabled(entity)) {
     // TODO Could we reuse the result of compositeDataToMemoryUsage?
     builder
         .pollAttribute(
             new JmxAttributePollConfig<Long>(UsesJavaMXBeans.USED_HEAP_MEMORY)
                 .objectName(ManagementFactory.MEMORY_MXBEAN_NAME)
                 .attributeName("HeapMemoryUsage")
                 .onSuccess(
                     (Function)
                         HttpValueFunctions.chain(
                             compositeDataToMemoryUsage(),
                             new Function<MemoryUsage, Long>() {
                               @Override
                               public Long apply(MemoryUsage input) {
                                 return (input == null) ? null : input.getUsed();
                               }
                             })))
         .pollAttribute(
             new JmxAttributePollConfig<Long>(UsesJavaMXBeans.INIT_HEAP_MEMORY)
                 .objectName(ManagementFactory.MEMORY_MXBEAN_NAME)
                 .attributeName("HeapMemoryUsage")
                 .onSuccess(
                     (Function)
                         HttpValueFunctions.chain(
                             compositeDataToMemoryUsage(),
                             new Function<MemoryUsage, Long>() {
                               @Override
                               public Long apply(MemoryUsage input) {
                                 return (input == null) ? null : input.getInit();
                               }
                             })))
         .pollAttribute(
             new JmxAttributePollConfig<Long>(UsesJavaMXBeans.COMMITTED_HEAP_MEMORY)
                 .objectName(ManagementFactory.MEMORY_MXBEAN_NAME)
                 .attributeName("HeapMemoryUsage")
                 .onSuccess(
                     (Function)
                         HttpValueFunctions.chain(
                             compositeDataToMemoryUsage(),
                             new Function<MemoryUsage, Long>() {
                               @Override
                               public Long apply(MemoryUsage input) {
                                 return (input == null) ? null : input.getCommitted();
                               }
                             })))
         .pollAttribute(
             new JmxAttributePollConfig<Long>(UsesJavaMXBeans.MAX_HEAP_MEMORY)
                 .objectName(ManagementFactory.MEMORY_MXBEAN_NAME)
                 .attributeName("HeapMemoryUsage")
                 .onSuccess(
                     (Function)
                         HttpValueFunctions.chain(
                             compositeDataToMemoryUsage(),
                             new Function<MemoryUsage, Long>() {
                               @Override
                               public Long apply(MemoryUsage input) {
                                 return (input == null) ? null : input.getMax();
                               }
                             })))
         .pollAttribute(
             new JmxAttributePollConfig<Long>(UsesJavaMXBeans.NON_HEAP_MEMORY_USAGE)
                 .objectName(ManagementFactory.MEMORY_MXBEAN_NAME)
                 .attributeName("NonHeapMemoryUsage")
                 .onSuccess(
                     (Function)
                         HttpValueFunctions.chain(
                             compositeDataToMemoryUsage(),
                             new Function<MemoryUsage, Long>() {
                               @Override
                               public Long apply(MemoryUsage input) {
                                 return (input == null) ? null : input.getUsed();
                               }
                             })))
         .pollAttribute(
             new JmxAttributePollConfig<Integer>(UsesJavaMXBeans.CURRENT_THREAD_COUNT)
                 .objectName(ManagementFactory.THREAD_MXBEAN_NAME)
                 .attributeName("ThreadCount"))
         .pollAttribute(
             new JmxAttributePollConfig<Integer>(UsesJavaMXBeans.PEAK_THREAD_COUNT)
                 .objectName(ManagementFactory.THREAD_MXBEAN_NAME)
                 .attributeName("PeakThreadCount"))
         .pollAttribute(
             new JmxAttributePollConfig<Long>(UsesJavaMXBeans.START_TIME)
                 .objectName(ManagementFactory.RUNTIME_MXBEAN_NAME)
                 .period(60, TimeUnit.SECONDS)
                 .attributeName("StartTime"))
         .pollAttribute(
             new JmxAttributePollConfig<Long>(UsesJavaMXBeans.UP_TIME)
                 .objectName(ManagementFactory.RUNTIME_MXBEAN_NAME)
                 .period(60, TimeUnit.SECONDS)
                 .attributeName("Uptime"))
         .pollAttribute(
             new JmxAttributePollConfig<Double>(UsesJavaMXBeans.PROCESS_CPU_TIME)
                 .objectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME)
                 .attributeName("ProcessCpuTime")
                 .onSuccess((Function) MathFunctions.times(0.001 * 0.001))) // nanos to millis
         .pollAttribute(
             new JmxAttributePollConfig<Double>(UsesJavaMXBeans.SYSTEM_LOAD_AVERAGE)
                 .objectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME)
                 .attributeName("SystemLoadAverage"))
         .pollAttribute(
             new JmxAttributePollConfig<Integer>(UsesJavaMXBeans.AVAILABLE_PROCESSORS)
                 .objectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME)
                 .period(60, TimeUnit.SECONDS)
                 .attributeName("AvailableProcessors"))
         .pollAttribute(
             new JmxAttributePollConfig<Long>(UsesJavaMXBeans.TOTAL_PHYSICAL_MEMORY_SIZE)
                 .objectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME)
                 .period(60, TimeUnit.SECONDS)
                 .attributeName("TotalPhysicalMemorySize"))
         .pollAttribute(
             new JmxAttributePollConfig<Long>(UsesJavaMXBeans.FREE_PHYSICAL_MEMORY_SIZE)
                 .objectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME)
                 .period(60, TimeUnit.SECONDS)
                 .attributeName("FreePhysicalMemorySize"));
     // FIXME: need a new type of adapter that maps multiple objectNames to a mapping
     // jmxAdapter.objectName(ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",*").with {
     //     attribute("SystemLoadAverage").subscribe(UsesJavaMXBeans.GARBAGE_COLLECTION_TIME, { def
     // m -> log.info("XXXXXXX $m") });
     // }
   }
   return builder;
 }