package com.linkedin.databus.core.monitoring.mbean;
/*
*
* Copyright 2013 LinkedIn Corp. All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.management.MBeanServer;
import com.linkedin.databus.core.monitoring.StatsCollectorCallback;
/**
* This class divides the StatsCollectorMergeable instances that are added to this class
* into "buckets". It uses one "StatsCollectors" instance per bucket to merge all
* StatsCollectorMergeable instances falling to same buckets.
*
* It also provides registration API for registering callback to listen to bucket
* collector's add/remove events
*
* A typical use of this is where we want to merge all relay stats belonging to one DB. A
* single relay can host multiple physical partitions belonging to different databases. In
* this case, all the partition specific StatsCollectorMergeable instances belonging to
* one database are considered one "bucket" and merged using StatsCollectors instance.
*
* This class is not thread-safe w.r.t addition/removal of
* StatsCollector/StatsCollectorCallback.
*/
public abstract class AbstractStatsCollectorsPartitioner<T extends StatsCollectorMergeable<T>>
{
/**
* Map between bucket name to StatsCollectors
*/
private final Map<String, StatsCollectors<T>> _statCollectorsMap;
/**
* MBeanServer
*/
private final MBeanServer _mbeanServer;
/**
* Callback for addition/removal of statsCollectors objects
*/
private StatsCollectorCallback<StatsCollectors<T>> _statsCallback;
// Mbean Owner id
private final int _ownerId;
// Suffix to the MbeanName ( ".inbound", ".outbound", etc)
protected final String _mbeanNameSuffix;
/**
* @param ownerId
* : Owner Id
* @param suffix
* : Suffix to be added to mbean name for bucket collectors
* @param mbeanServer
* : MBeanServer to register/deregister
*/
public AbstractStatsCollectorsPartitioner(int ownerId,
String suffix,
MBeanServer mbeanServer)
{
_statCollectorsMap = new HashMap<String, StatsCollectors<T>>();
_mbeanServer = mbeanServer;
_ownerId = ownerId;
_mbeanNameSuffix = suffix;
}
/**
* Stats Collector Merger for an individual bucket
*
* @param bucketName
* bucket Name
* @return
*/
protected StatsCollectors<T> getBucketStatsCollector(String bucketName)
{
return _statCollectorsMap.get(bucketName);
}
/**
* Add the individual StatsCollectorMergeable instance.
*
* @param bucketKey
* : Key used to locate the StatsCollectors instance which merges all
* "StatsCollectorMergeable" instances belonging to one bucket
* @param key
* : Key used to identify "StatsCollectorMergeable" instance within
* the bucket
* @param collector
* : StatsCollectorMergeable to be added to the partition
*/
protected void addStatsCollector(String bucketKey, String key, T collector)
{
StatsCollectors<T> c = _statCollectorsMap.get(bucketKey);
if (null == c)
{
c = createStatsCollector(_ownerId, bucketKey, _mbeanServer);
_statCollectorsMap.put(bucketKey, c);
notifyStatsAdd(c);
}
c.addStatsCollector(key, collector);
}
/**
* De-register all stats collectors and remove from MBeanServer.
*/
public void removeAllStatsCollector()
{
Iterator<Entry<String, StatsCollectors<T>>> itr =
_statCollectorsMap.entrySet().iterator();
while (itr.hasNext())
{
StatsCollectors<T> c = itr.next().getValue();
unregisterStatsCollector(c);
notifyStatsRemove(c);
itr.remove();
}
}
/**
* Notify the stats callback when bucket (merger) collector is added.
*
* @param collector
*/
private void notifyStatsAdd(StatsCollectors<T> collector)
{
if (null != _statsCallback)
{
_statsCallback.addedStats(collector);
}
}
/**
* Notify the stats callback when bucket (merger) collector is removed.
*
* @param collector
*/
private void notifyStatsRemove(StatsCollectors<T> collector)
{
if (null != _statsCallback)
{
_statsCallback.removedStats(collector);
}
}
/**
* Register the stats callback to get notification when bucket (merger) collector is
* added/removed.
*
* @param collector
*/
public void registerStatsCallback(StatsCollectorCallback<StatsCollectors<T>> statsCallback)
{
_statsCallback = statsCallback;
// Trigger callback for those collectors that were already added
for (Entry<String, StatsCollectors<T>> e : _statCollectorsMap.entrySet())
{
notifyStatsAdd(e.getValue());
}
}
/**
* Factory to instantiate the bucket collector. This is invoked the first time an
* StatsCollectorMergeable gets added to a bucket.
*
* @param ownerId
* Owner Id
* @param suffix
* Suffix name to add to the name of the bucket collector
* @param server
* Mbean Server
* @return
*/
protected abstract StatsCollectors<T> createStatsCollector(int ownerId,
String suffix,
MBeanServer server);
/**
* Unregister the bucket stats collector from mbean server.
*/
protected abstract void unregisterStatsCollector(StatsCollectors<T> collector);
}