/**
* Helios, OpenSource Monitoring
* Brought to you by the Helios Development Group
*
* Copyright 2007, Helios Development Group and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
*/
package org.helios.apmrouter.byteman.sockets;
import org.helios.apmrouter.util.SimpleLogger;
import java.util.concurrent.atomic.AtomicReference;
import static org.helios.apmrouter.util.Methods.nvl;
/**
* <p>Title: SocketTracingLevel</p>
* <p>Description: Functional Enumeration of the levels of verbosity available for the socket monitor </p>
* <p>Company: Helios Development Group LLC</p>
* @author Whitehead (nwhitehead AT heliosdev DOT org)
* <p><code>org.helios.apmrouter.byteman.SocketTracingLevel</code></p>
*/
public enum SocketTracingLevel {
/** Traces active connections only */
CONNECTIONS(false, false),
/** Traces active connections and traffic by address */
ADDRESS_TRAFFIC(true, false),
/** Traces active connections and traffic by address/port */
PORT_TRAFFIC(false, true),
/** Traces active connections and traffic by address/port, and summary by address */
ADDRESS_PORT_TRAFFIC(false, true);
/**
* Creates a new SocketTracingLevel
* @param addressCollecting Indicates if this level implements collecting by address
* @param portCollecting Indicates if this level implements collecting by address/port
*/
private SocketTracingLevel(boolean addressCollecting, boolean portCollecting) {
this.addressCollecting = addressCollecting;
this.portCollecting = portCollecting;
}
/** Indicates if this level implements collecting by address */
private final boolean addressCollecting;
/** Indicates if this level implements collecting by address */
private final boolean portCollecting;
/** The name of the system property the specifies the socket tracing level */
public static final String LEVEL_PROP = "org.helios.apmrouter.socketlevel";
/**
* Indicates if this level implements active connections only
* @return true if this level implements active connections only, false otherwise
*/
public boolean isActiveConnections() {
return !addressCollecting && !portCollecting;
}
/**
* Indicates if this level implements collecting by address
* @return true if this level implements collecting by address, false otherwise
*/
public boolean isAddressCollecting() {
return addressCollecting;
}
/**
* Indicates if this level implements collecting by address and port
* @return true if this level implements collecting by address and port, false otherwise
*/
public boolean isPortCollecting() {
return portCollecting;
}
/**
* Decodes the passed name to a SocketTracingLevel level.
* Throws a runtime exception if the name is invalid
* @param name The SocketTracingLevel name to decode. Trimmed and uppercased.
* @return the decoded SocketMetric
*/
public static SocketTracingLevel valueOfName(CharSequence name) {
String n = nvl(name, "SocketTracingLevel Name").toString().trim().toUpperCase();
try {
return SocketTracingLevel.valueOf(n);
} catch (Exception e) {
throw new IllegalArgumentException("The passed name [" + name + "] is not a valid SocketTracingLevel name", new Throwable());
}
}
/**
* Reads the system property named {@literal SocketTracingLevel#LEVEL_PROP} and returns the configured level.
* If the level is not configured, or the configured name is invalid, returns {@link SocketTracingLevel#CONNECTIONS}.
* @return the configured SocketTracingLevel.
*/
public static SocketTracingLevel getLevel() {
String prop = System.getProperty(LEVEL_PROP, null);
if(prop==null) {
System.setProperty(LEVEL_PROP, CONNECTIONS.name());
return CONNECTIONS;
}
try {
return valueOfName(prop);
} catch (Exception ex) {
SimpleLogger.warn("Invalid SocketTracingLevel Specified [", prop, "]. Setting to the default level of CONNECTIONS");
System.setProperty(LEVEL_PROP, CONNECTIONS.name());
return CONNECTIONS;
}
}
/**
* <p>Title: SocketTracingLevelListener</p>
* <p>Description: Defines an interface for listeners that need to be notified of changes in a specified SocketTracingLevel.</p>
* <p>Company: Helios Development Group LLC</p>
* @author Whitehead (nwhitehead AT heliosdev DOT org)
* <p><code>org.helios.apmrouter.byteman.SocketTracingLevel.SocketTracingLevelListener</code></p>
*/
public static interface SocketTracingLevelListener {
/**
* Fired when the old value was null and the new value is the passed value
* @param newLevel the new SocketTracingLevel
*/
public void fromNullTo(SocketTracingLevel newLevel);
/**
* Fired when the old value is replace by null
* @param oldLevel the new SocketTracingLevel
*/
public void toNull(SocketTracingLevel oldLevel);
/**
* Fired when the old value is replaced with the new value
* @param oldLevel The prior value
* @param newLevel the new SocketTracingLevel
*/
public void change(SocketTracingLevel oldLevel, SocketTracingLevel newLevel);
}
/**
* <p>Title: EmptySocketTracingLevelListener</p>
* <p>Description: An empty implementation of {@link SocketTracingLevelListener} for simple extending.</p>
* <p>Company: Helios Development Group LLC</p>
* @author Whitehead (nwhitehead AT heliosdev DOT org)
* <p><code>org.helios.apmrouter.byteman.SocketTracingLevel.EmptySocketTracingLevelListener</code></p>
*/
public static class EmptySocketTracingLevelListener implements SocketTracingLevelListener {
/**
* {@inheritDoc}
* @see org.helios.apmrouter.byteman.sockets.SocketTracingLevel.SocketTracingLevelListener#fromNullTo(org.helios.apmrouter.byteman.sockets.SocketTracingLevel)
*/
@Override
public void fromNullTo(SocketTracingLevel newLevel) {
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.byteman.sockets.SocketTracingLevel.SocketTracingLevelListener#toNull(org.helios.apmrouter.byteman.sockets.SocketTracingLevel)
*/
@Override
public void toNull(SocketTracingLevel oldLevel) {
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.byteman.sockets.SocketTracingLevel.SocketTracingLevelListener#change(org.helios.apmrouter.byteman.sockets.SocketTracingLevel, org.helios.apmrouter.byteman.sockets.SocketTracingLevel)
*/
@Override
public void change(SocketTracingLevel oldLevel, SocketTracingLevel newLevel) {
}
}
/**
* <p>Title: SocketTracingLevelWatcher</p>
* <p>Description: A convenience implementation of a {@link SocketTracingLevel} container that fires {@link SocketTracingLevelListener} events when the value changes.</p>
* <p>Company: Helios Development Group LLC</p>
* @author Whitehead (nwhitehead AT heliosdev DOT org)
* <p><code>org.helios.apmrouter.byteman.SocketTracingLevelWatcher</code></p>
*/
public static class SocketTracingLevelWatcher {
/** The supplied listener */
private final SocketTracingLevelListener listener;
/** The container for the level */
private final AtomicReference<SocketTracingLevel> level = new AtomicReference<SocketTracingLevel>(null);
/**
* Creates a new SocketTracingLevelWatcher
* @param initialLevel The initial level to install. Ignored if null
* @param listener The listener that will be called back on when the level is changed
*/
public SocketTracingLevelWatcher(SocketTracingLevel initialLevel, SocketTracingLevelListener listener) {
this.listener = nvl(listener, "Null listener");
if(initialLevel!=null) {
level.set(initialLevel);
}
}
/**
* Creates a new SocketTracingLevelWatcher with a null initial value
* @param listener The listener that will be called back on when the level is changed
*/
public SocketTracingLevelWatcher(SocketTracingLevelListener listener) {
this(null, listener);
}
/**
* Returns the current level
* @return the current level
*/
public SocketTracingLevel get() {
return level.get();
}
/**
* Sets the level
* @param newLevel level to set
*/
public void set(final SocketTracingLevel newLevel) {
final SocketTracingLevel oldLevel = level.getAndSet(newLevel);
if(newLevel==null) {
if(oldLevel==null) {
// null to null. No action
} else {
// switched to null
listener.toNull(oldLevel);
}
} else {
if(oldLevel==null) {
// from null to new
listener.fromNullTo(newLevel);
} else {
// from old to new
listener.change(oldLevel, newLevel);
}
}
}
/**
* {@inheritDoc}
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
SocketTracingLevel stl = level.get();
return stl==null ? "null" : stl.name();
}
}
}