![JAR search and dependency download from the Maven repository](/logo.png)
io.pcp.parfait.MonitorableRegistry Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of parfait-core Show documentation
Show all versions of parfait-core Show documentation
Java performance monitoring framework, including PCP bridge
The newest version!
/*
* Copyright 2009-2017 Aconex
*
* 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.
*/
package io.pcp.parfait;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
/**
* A collection of Monitorables to be monitored by a given output source (or
* sources). Each {@link Monitorable} is associated with a particular
* MonitorableRegistry, and informs the registry of its own details via a
* callback to {@link #register(Monitorable)} when the Monitorable is created.
* the MonitorableRegistryListener interface can be used for clients interested in state changes
* to be made aware of when new Monitorables are added, such as objects that wish
* to serialize state to external stores. (ie... A PCPmmvWriter.. say..)
*/
public class MonitorableRegistry {
private static final ConcurrentMap NAMED_INSTANCES = new ConcurrentHashMap();
/**
* A single central registry which can be used by non-Registry-aware
* Monitorables. This is very limiting in terms of system flexibility and an
* explicit {@link MonitorableRegistry} should be used instead.
*/
public static MonitorableRegistry DEFAULT_REGISTRY = new MonitorableRegistry();
/**
* This is a TreeMap so that the Monitorables are maintained in alphabetical
* order for convenience.
*/
private final Map> monitorables = new TreeMap>();
private final List registryListeners = new CopyOnWriteArrayList();
/**
* Informs this MonitorableRegistry of a new {@link Monitorable}; that
* Monitorable will be added to the registry, assuming no Monitorable with
* the same name has previously been registered.
*
* @throws UnsupportedOperationException
* if the name of the provided monitorable has already been
* registered
*/
public synchronized void register(Monitorable monitorable) {
if (monitorables.containsKey(monitorable.getName())) {
throw new UnsupportedOperationException(
"There is already an instance of the Monitorable [" + monitorable.getName()
+ "] registered.");
}
monitorables.put(monitorable.getName(), monitorable);
notifyListenersOfNewMonitorable(monitorable);
}
/**
* Registers the monitorable if it does not already exist, but otherwise returns an already registered
* Monitorable with the same name, Semantics and UNnit definition. This method is useful when objects
* appear and disappear, and then return, and the lifecycle of the application requires an attempt to recreate
* the Monitorable without knowing if it has already been created.
*
* If there exists a Monitorable with the same name, but with different Semantics or Unit then an IllegalArgumentException
* is thrown.
*
*/
@SuppressWarnings("unchecked")
public synchronized T registerOrReuse(Monitorable monitorable) {
String name = monitorable.getName();
if (monitorables.containsKey(name)) {
Monitorable> existingMonitorableWithSameName = monitorables.get(name);
if (monitorable.getSemantics().equals(existingMonitorableWithSameName.getSemantics()) && monitorable.getUnit().equals(existingMonitorableWithSameName.getUnit())) {
return (T) existingMonitorableWithSameName;
} else {
throw new IllegalArgumentException(String.format("Cannot reuse the same name %s for a monitorable with different Semantics or Unit: requested=%s, existing=%s", name, monitorable, existingMonitorableWithSameName));
}
} else {
monitorables.put(name, monitorable);
notifyListenersOfNewMonitorable(monitorable);
return (T) monitorable;
}
}
private void notifyListenersOfNewMonitorable(Monitorable> monitorable) {
for (MonitorableRegistryListener listener : registryListeners) {
listener.monitorableAdded(monitorable);
}
}
/**
* @return a list of all Monitorables which are registered with this
* MonitorableRegistry.
*/
public synchronized Collection> getMonitorables() {
return ImmutableList.copyOf(monitorables.values());
}
/*
* Testing only -- should be eliminated once the default registry is gone
*/
public static void clearDefaultRegistry() {
DEFAULT_REGISTRY = new MonitorableRegistry();
}
/**
* Retrieves or creates a centrally-accessible named instance, identified
* uniquely by the provided String. This is a convenience method to bridge
* between the old-style 'single registry' model (see
* {@link #DEFAULT_REGISTRY}) and having to pass a MonitorableRegistry down
* to the very depths of your class hierarchy. This is especially useful
* when instrumenting third-party code which cannot easily get access to a
* given MonitorableRegistry from a non-static context.
*
* @param name
* @return
*/
public static MonitorableRegistry getNamedInstance(String name) {
MonitorableRegistry instance = NAMED_INSTANCES.get(name);
if (instance == null) {
instance = new MonitorableRegistry();
MonitorableRegistry existing = NAMED_INSTANCES.putIfAbsent(name, instance);
if (existing != null) {
return existing;
}
}
return instance;
}
public void addRegistryListener(MonitorableRegistryListener monitorableRegistryListener) {
this.registryListeners.add(monitorableRegistryListener);
}
public void removeRegistryListener(MonitorableRegistryListener listener) {
this.registryListeners.remove(listener);
}
@VisibleForTesting
boolean containsMetric(String name) {
return monitorables.containsKey(name);
}
@VisibleForTesting
Monitorable> getMetric(String name) {
return monitorables.get(name);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy