/**
* 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.dataservice.json.catalog;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Array;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.apache.log4j.Logger;
import org.helios.apmrouter.cache.CacheStatistics;
import org.helios.apmrouter.catalog.EntryStatus;
import org.helios.apmrouter.catalog.domain.Metric;
import org.helios.apmrouter.jmx.ConfigurationHelper;
import org.helios.apmrouter.metric.MetricType;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.json.JSONArray;
import org.json.JSONObject;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
/**
* <p>Title: MetricURI</p>
* <p>Description: Represents a metric query or set definition in the form of a <b><code>URI</code></b>.</p>
* <p>Components:<ol>
* <li>The URI representing the domain down to a specific folder</li>
* <li><b>path:</b>The path of the URI representing the path of the metric from the domain down to the specified folder. Breaks out into:<ul>
* <li><b>Domain</b></li>
* <li><b>Host</b></li>
* <li><b>Agent</b></li>
* <li><b>Namespace</b></li>
* </ul></li>
* <li><b>maxdepth:</b></li>
* <li><b>metrictype:</b></li>
* <li><b>status:</b></li>
* </ol></p>
* <p>Company: Helios Development Group LLC</p>
* @author Whitehead (nwhitehead AT heliosdev DOT org)
* <p><code>org.helios.apmrouter.dataservice.json.catalog.MetricURI</code></p>
*/
public class MetricURI implements MetricURIMBean {
/** The full URI */
protected final URI metricUri;
/** The metric domain */
protected final String domain;
/** The metric host */
protected final String host;
/** The metric agent */
protected final String agent;
/** The metric namespace */
protected final String namespace;
/** Indicates if the query is recursive */
protected final boolean recursive;
/** The maximum depth of the query */
protected final int maxDepth;
/** The metric name expression */
protected final String metricName;
/** The metric data types */
protected final int[] metricType;
/** The metric data type mask */
protected final int metricTypeMask;
/** The metric statuses */
protected final byte[] metricStatus;
/** The metric status mask */
protected final byte metricStatusMask;
/** A mask representing the metric type, status and subscription type (mask of int/byte/byte) */
protected final long metricTypeStatusSubTypeMask;
/** The hibernate detached criteria */
protected final DetachedCriteria detachedCriteria;
/** The metric Id retrieveal sql */
protected final String metricIdSql;
/** The bit mask of the metric subscription types requested */
protected final byte subscriptionType;
/** The URI parameter parser */
public static final Pattern PARM_PARSER = Pattern.compile("&");
/** The URI parameter pair parser */
public static final Pattern PARM_PAIR_PARSER = Pattern.compile("=");
/** The URI path parser */
public static final Pattern PATH_PARSER = Pattern.compile("/");
/** The comma parser */
public static final Pattern COM_PARSER = Pattern.compile(",");
/** The name bit parser*/
public static final Pattern NAME_BIT_PARSER = Pattern.compile(":");
/** Option key for a recursive query */
public static final String OPT_RECURSIVE = "rec";
/** Option key for the max depth of the query */
public static final String OPT_MAX_DEPTH = "maxd";
/** Option key for the metric type filter of the query, parse as comma separated ints */
public static final String OPT_METRIC_TYPE = "type";
/** Option key for the status filter of the query, parse as comma separated ints */
public static final String OPT_METRIC_STATUS = "st";
/** Option key for the subscription type bit mask */
public static final String OPT_SUB_TYPE = "subtype";
/** The default max depth */
private static final int[] DEFAULT_DEPTH = new int[]{-1};
/** The default metric types */
private static final int[] DEFAULT_TYPES;
/** The default metric types */
private static final byte[] DEFAULT_SUB_TYPES = MetricURISubscriptionType.getAllSubTypeOrdinals();
/** The default metric statuses */
private static final byte[] DEFAULT_METRIC_STATUS = new byte[]{0,1,2};
/** The escaped single character wild card */
public static final String ONE_CHAR_WILDCARD = "\\_";
/** The escaped multiple character wild card */
public static final String MULTI_CHAR_WILDCARD = "\\%";
// =======================================================================
// MetricURI caching configuration and impl
// =======================================================================
/** The system property or env variable name that overrides the default max cache size (@link {@value #DEFAULT_METRIC_URI_CACHE_MAXSIZE} */
public static final String METRIC_URI_CACHE_MAXSIZE_PROP = "org.helios.metricuri.maxsize";
/** The default max cache size */
public static final long DEFAULT_METRIC_URI_CACHE_MAXSIZE = 500;
/** A cache of MetricURIs keyed by the string value of the URI */
private static LoadingCache<String, MetricURI> metricURICache;
/** The cache stats for the metricURICache */
private static final CacheStatistics cacheStatistics;
// =======================================================================
/** Static class logger */
protected static final Logger LOG = Logger.getLogger(MetricURI.class);
static {
MetricType[] longTypes = MetricType.getLongMetricTypes();
int[] longCodes = new int[longTypes.length];
for(int i = 0; i < longTypes.length; i++) {
longCodes[i] = longTypes[i].ordinal();
}
DEFAULT_TYPES = longCodes;
metricURICache = CacheBuilder.newBuilder().softValues().recordStats()
.maximumSize(ConfigurationHelper.getLongSystemThenEnvProperty(METRIC_URI_CACHE_MAXSIZE_PROP, DEFAULT_METRIC_URI_CACHE_MAXSIZE))
.build(new CacheLoader<String, MetricURI>(){
@Override
public MetricURI load(String key) throws Exception {
return new MetricURI(key);
}
});
cacheStatistics = new CacheStatistics(metricURICache, "MetricURI");
cacheStatistics.register();
}
/**
* Returns a MetricURI for the passed string representation
* @param uri The URI string representation
* @return a MetricURI
*/
public static MetricURI getMetricURI(CharSequence uri) {
if(uri==null || uri.toString().trim().isEmpty()) throw new RuntimeException("The passed URI was empty or null", new Throwable());
try {
return getMetricURI(new URI(uri.toString().trim()));
} catch (Exception ex) {
throw new RuntimeException("Failed to create MetricURI for [" + uri + "]", ex);
}
}
/**
* Returns a MetricURI for the passed {@link URI}
* @param uri The URI
* @return a MetricURI
*/
public static MetricURI getMetricURI(final URI uri) {
if(uri==null) throw new RuntimeException("The passed URI was null", new Throwable());
final String key = uri.toString().trim();
try {
return metricURICache.get(key);
} catch (Exception ex) {
throw new RuntimeException("Failed to create MetricURI for [" + uri + "]", ex);
}
}
/**
* Creates a new MetricURI
* @param uri The URI string content
*/
private MetricURI(CharSequence uri) {
this(toURI(uri));
}
/**
* Computes the mask of all the passed ints
* @param ints the ints to compute the masks for
* @return the mask
*/
protected int mask(int[] ints) {
if(ints==null || ints.length==0) return 0;
int start = 0;
for(int entry: ints) {
start = (start | entry);
}
return start;
}
/**
* Determines if the passed mask is a match for this metric uri
* @param mask the mask to test
* @return true for a match, false otherwise
*/
public boolean matches(long mask) {
return 0 != (this.metricTypeStatusSubTypeMask & mask);
}
/**
* Creates a new MetricURI
* @param uri The URI to build this MetricURI with
*/
private MetricURI(URI uri) {
if(uri==null) throw new IllegalArgumentException("Passed URI was null", new Throwable());
metricUri = uri;
String path = uri.getPath();
if(path==null || path.trim().isEmpty()) {
throw new IllegalArgumentException("Unexpected empty or null path", new Throwable());
}
String cleanedPath = null;
String uriPath = uri.getPath().trim();
int cIndex = uriPath.lastIndexOf(':');
if(cIndex==-1) {
cleanedPath = uriPath;
metricName = null;
} else {
String[] bitsOfPath = NAME_BIT_PARSER.split(uriPath);
if(bitsOfPath.length>2) {
cleanedPath = uriPath.substring(0, cIndex);
metricName = uriPath.substring(cIndex).replace('*', '%');
} else {
metricName = bitsOfPath[1].replace('*', '%');
cleanedPath = bitsOfPath[0];
}
}
String[] splitPath = PATH_PARSER.split(cleanedPath);
if(splitPath.length<3) {
throw new IllegalArgumentException("Unexpected path length (<3) [" + uri + "]", new Throwable());
}
domain = splitPath[0].replace('*', '%');
host = splitPath[1].replace('*', '%');
agent = splitPath[2].replace('*', '%');
if(splitPath.length>3) {
StringBuilder b = new StringBuilder();
for(int i = 3; i < splitPath.length; i++) {
b.append("/").append(splitPath[i]);
}
namespace = b.toString().replace('*', '%');
} else {
namespace = null;
}
Map<String, String> paramMap = new HashMap<String, String>();
if(uri.getQuery()!=null) {
for(String pair: PARM_PARSER.split(uri.getQuery())) {
if(pair==null || pair.trim().isEmpty() || pair.indexOf('=')==-1) continue;
String[] paramPair = PARM_PAIR_PARSER.split(pair);
paramMap.put(paramPair[0].trim().toLowerCase(), paramPair[1].trim());
}
}
recursive = opt(paramMap, OPT_RECURSIVE, false);
maxDepth = opt(paramMap, OPT_MAX_DEPTH, DEFAULT_DEPTH)[0];
metricType = getTypes(paramMap);
metricTypeMask = MetricType.getMaskFor(metricType);
metricStatus = opt(paramMap, OPT_METRIC_STATUS, DEFAULT_METRIC_STATUS);
metricStatusMask = EntryStatus.getMaskFor(metricStatus);
detachedCriteria = generateCriteria(this);
metricIdSql = generateCriteriaSQL(this);
subscriptionType = getSubTypeMask(paramMap);
metricTypeStatusSubTypeMask = mask(metricTypeMask, metricStatusMask, subscriptionType);
}
private static final byte ZERO_BYTE = 0;
/**
* Computes a long mask that represents the enabled metric types, metric statuses and subscription types.
* @param metricTypeMask The enabled metric type mask
* @param metricStatusMask The enabled metric status mask
* @param subTypeMask The enabled subscription type mask
* @return a mask that represents the enabled metric types, metric statuses and subscription types.
*/
public static long mask(int metricTypeMask, byte metricStatusMask, byte subTypeMask) {
ByteBuffer buff = ByteBuffer.allocate(8).put(ZERO_BYTE).put(ZERO_BYTE)
.putInt(metricTypeMask)
.put(metricStatusMask)
.put(subTypeMask);
buff.flip();
return buff.getLong();
}
/**
* Detemines if this MetricURI is a match for the passed mask representing enabled metric types, metric statuses and subscription types
* @param metricTypeStatusSubTypeMask a long mask representing enabled metric types, metric statuses and subscription types
* @return true for a match, false otherwise
*/
public boolean isEnabledFor(long metricTypeStatusSubTypeMask) {
return metricTypeStatusSubTypeMask==(this.metricTypeStatusSubTypeMask | metricTypeStatusSubTypeMask);
}
/**
* Detemines if this MetricURI is a match for the passed metric type, metric status and subscription type
* @param metricType The metric type ordinal
* @param metricStatus The metric status ordinal
* @param subscriptionType The subscription type ordinal
* @return true for a match, false otherwise
*/
public boolean isEnabledFor(int metricType, byte metricStatus, byte subscriptionType) {
return metricTypeStatusSubTypeMask==(this.metricTypeStatusSubTypeMask | mask(metricType, metricStatus, subscriptionType));
}
/**
* Returns the enabled subscription type bit mask
* @return the enabled subscription type bit mask
*/
@Override
public byte getSubscriptionType() {
return subscriptionType;
}
/**
* Returns a pipe delimited string of the enabled subscription type names
* @return a pipe delimited string of the enabled subscription type names
*/
@Override
public String getSubscriptionTypeNames() {
return MetricURISubscriptionType.getNamesFor(subscriptionType);
}
/**
* Determines if this MetricURI is enabled for the passed subscription type
* @param subType the subscription type to test for
* @return true if this MetricURI is enabled for the passed subscription type , false otherwise
*/
public boolean isEnabledFor(MetricURISubscriptionType subType) {
return subType.isEnabled(subscriptionType);
}
/**
* Generates a JSON string representing this MetricURI using the compact ordinal representation of the options
* @return a JSON string
*/
public String toJSON(boolean compact) {
try {
JSONObject jo = new JSONObject();
jo.put("domain", domain);
jo.put("host", host);
jo.put("agent", agent);
jo.put("namespace", namespace);
jo.put("metricname", metricName);
jo.put("maxdepth", maxDepth);
jo.put("metrictypes", getMetricTypesAsJsonArray(compact));
jo.put("metrictstatus", getMetricStatusesAsJsonArray(compact));
jo.put("subtypes", getSubTypesAsJsonArray(compact));
return jo.toString();
} catch (Exception ex) {
throw new RuntimeException("Failed to create compact JSON", ex);
}
}
/**
* Generates a JSONArray for this MetricURI's subscription types
* @param compact If true, uses the enum ordinals, otherwise uses the full name
* @return a JSONArray of this MetricURI's subscription types
*/
public JSONArray getSubTypesAsJsonArray(boolean compact) {
JSONArray mtypes = new JSONArray();
for(MetricURISubscriptionType st: MetricURISubscriptionType.getEnabledFor(subscriptionType)) {
mtypes.put(compact ? st.ordinal() : st.name());
}
return mtypes;
}
/**
* Generates a JSONArray for this MetricURI's metric types
* @param compact If true, uses the enum ordinals, otherwise uses the full name
* @return a JSONArray of this MetricURI's metric types
*/
public JSONArray getMetricTypesAsJsonArray(boolean compact) {
JSONArray mtypes = new JSONArray();
for(int i: metricType) {
mtypes.put(compact ? i : MetricType.valueOf(i).name());
}
return mtypes;
}
/**
* Generates a JSONArray for this MetricURI's metric statuses
* @param compact If true, uses the enum ordinals, otherwise uses the full name
* @return a JSONArray of this MetricURI's metric statuses
*/
public JSONArray getMetricStatusesAsJsonArray(boolean compact) {
JSONArray mtypes = new JSONArray();
for(EntryStatus es: EntryStatus.getEnabledFor(metricStatusMask)) {
mtypes.put(compact ? es.ordinal() : es.name());
}
return mtypes;
}
/**
* {@inheritDoc}
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("MetricURI [");
builder.append("\n\tdomain:");
builder.append(domain);
builder.append("\n\thost:");
builder.append(host);
builder.append("\n\tagent:");
builder.append(agent);
builder.append("\n\tnamespace:");
builder.append(namespace);
builder.append("\n\tmaxDepth:");
builder.append(maxDepth);
builder.append("\n\tmetricName:");
builder.append(metricName);
builder.append("\n\tmetricTypes:");
builder.append(Arrays.toString(metricType));
builder.append("\n\tmetricStatus:");
builder.append(Arrays.toString(metricStatus));
builder.append("\n\tsubTypes:");
builder.append(Arrays.toString(MetricURISubscriptionType.getEnabledFor(subscriptionType)));
builder.append("\n]");
return builder.toString();
}
public static void main(String[] args) {
//new MetricURI("DefaultDomain/njw810/APMRouterServer/platform=os/resource=netstat?recursive=false&status=0|1");
MetricURI m = new MetricURI("DefaultDomain/njw810/APMRouterServer/platform=os/resource=netstat:FooBar?recursive=false&status=0,1");
try {
URI uri = new URI("DefaultDomain/njw810/APMRouterServer/platform=os/resource=netstat:FooBar?recursive=false&status=0,1");
log("URI Path" + uri.getPath());
} catch (Exception ex) {
ex.printStackTrace(System.err);
}
log("MetricURI:" + m);
}
public static void log(Object msg) {
System.out.println(msg);
}
// public static JSONArray enumArrayToJSONArray(Class<? extends Enum<?>> enumType, Object arr, boolean compact) {
// JSONArray jsonArray = new JSONArray();
// if(arr==null) return jsonArray;
// if(Enum.class.isInstance(arr)) {
// jsonArray.put(compact ? ((Enum)arr).ordinal() : ((Enum)arr).name());
// } else if(arr.getClass().isArray()) {
// Class<?> arrayType = arr.getClass().getComponentType();
// int arrSize = Array.getLength(arr);
// if(int.class.isAssignableFrom(arrayType)) {
// for(int i = 0; i < arrSize; i++) {
// int value = Array.getInt(arr, i);
// jsonArray.put(compact ? value : enumType.);
// }
// } else if(CharSequence.class.isAssignableFrom(arrayType)) {
//
// } else if(Enum.class.isAssignableFrom(arrayType)) {
//
// }
// } else {
// jsonArray.put(arr);
// }
// return jsonArray;
//}
/**
* Converts the passed string to a {@link URI}.
* @param uri The URI string value
* @return the created URI
*/
protected static URI toURI(CharSequence uri) {
if(uri==null) throw new IllegalArgumentException("Passed URI was null", new Throwable());
String urs = uri.toString().trim(); if(urs.isEmpty()) throw new IllegalArgumentException("Passed URI was empty", new Throwable());
try {
return new URI(urs);
} catch (Exception ex) {
throw new RuntimeException("Invalid URI [" + uri + "]", new Throwable());
}
}
/**
* Extracts a boolean argument from the parameter map
* @param optMap The parameter map
* @param key The parameter key
* @param defaultValue The default value
* @return the extracted value or default
*/
public static boolean opt(Map<String, String> optMap, String key, boolean defaultValue) {
if(optMap.containsKey(key)) {
return Boolean.parseBoolean(optMap.get(key));
}
return defaultValue;
}
/**
* Extracts an integer array argument from the parameter map
* @param optMap The parameter map
* @param key The parameter key
* @param defaultValue The default value
* @return the extracted value or default
*/
public static int[] opt(Map<String, String> optMap, String key, int[] defaultValue) {
if(optMap.containsKey(key)) {
String[] values = COM_PARSER.split(optMap.get(key));
int[] intValues = new int[values.length];
for(int i = 0; i < values.length; i++) {
intValues[i] = Integer.parseInt(values[i]);
}
return intValues;
}
return defaultValue;
}
/**
* Extracts a byte array argument from the parameter map
* @param optMap The parameter map
* @param key The parameter key
* @param defaultValue The default value
* @return the extracted value or default
*/
public static byte[] opt(Map<String, String> optMap, String key, byte[] defaultValue) {
if(optMap.containsKey(key)) {
String[] values = COM_PARSER.split(optMap.get(key));
byte[] byteValues = new byte[values.length];
for(int i = 0; i < values.length; i++) {
byteValues[i] = Byte.parseByte(values[i]);
}
return byteValues;
}
return defaultValue;
}
/**
* Extracts the type specifications from the option map
* @param optMap The option map
* @return an array of {@link MetricType} ordinals
*/
public static int[] getTypes(Map<String, String> optMap) {
if(optMap.containsKey(OPT_METRIC_TYPE)) {
String optValue = optMap.get(OPT_METRIC_TYPE);
if(optValue.trim().isEmpty()) return DEFAULT_TYPES;
String[] values = COM_PARSER.split(optValue);
int[] intValues = new int[values.length];
for(int i = 0; i < values.length; i++) {
intValues[i] = MetricType.valueOfName(values[i]).ordinal();
}
return intValues;
}
return DEFAULT_TYPES;
}
/**
* Extracts the subscription type bit mask from the option map
* @param optMap The option map
* @return a a bit mask representation of the enabled {@link MetricURISubscriptionType}s
*/
public static byte getSubTypeMask(Map<String, String> optMap) {
return MetricURISubscriptionType.enable(getSubTypes(optMap));
}
/**
* Extracts the subscription type specifications from the option map
* @param optMap The option map
* @return an array of {@link MetricURISubscriptionType} ordinals
*/
public static byte[] getSubTypes(Map<String, String> optMap) {
if(optMap.containsKey(OPT_SUB_TYPE)) {
String optValue = optMap.get(OPT_SUB_TYPE);
if(optValue.trim().isEmpty()) return DEFAULT_SUB_TYPES;
String[] values = COM_PARSER.split(optValue);
byte[] byteValues = new byte[values.length];
for(int i = 0; i < values.length; i++) {
byteValues[i] = MetricURISubscriptionType.valueOfName(values[i]).getCode();
}
return byteValues;
}
return DEFAULT_SUB_TYPES;
}
/**
* Generates a hibernate detached criteria for the passed MetricURI
* @param metricUri The MetricURI
* @return the detached criteria
*/
protected static DetachedCriteria generateCriteria(MetricURI metricUri) {
DetachedCriteria criteria = DetachedCriteria.forClass(Metric.class)
.createAlias("agent", "a")
.createAlias("traceType", "t")
.createAlias("a.host", "h");
if(!"%".equals(metricUri.domain)) {
criteria.add(metricUri.domain.indexOf('%')==-1 ?
Restrictions.eq("h.domain", metricUri.domain) :
Restrictions.like("h.domain", metricUri.domain));
}
if(!"%".equals(metricUri.host)) {
criteria.add(metricUri.host.indexOf('%')==-1 ?
Restrictions.eq("h.name", metricUri.host) :
Restrictions.like("h.name", metricUri.host));
}
if(!"%".equals(metricUri.agent)) {
criteria.add(metricUri.agent.indexOf('%')==-1 ?
Restrictions.eq("a.name", metricUri.agent) :
Restrictions.like("a.name", metricUri.agent));
}
// .add(Restrictions.eq("h.name", metricUri.host))
// .add(Restrictions.eq("a.name", metricUri.agent));
if(metricUri.maxDepth>0) {
criteria.add(Restrictions.and(
Restrictions.like("namespace", metricUri.namespace + "%"),
Restrictions.le("level", metricUri.maxDepth)
));
} else {
if(metricUri.namespace.indexOf('%')!=-1) {
criteria.add(Restrictions.like("namespace", metricUri.namespace));
} else {
criteria.add(Restrictions.eq("namespace", metricUri.namespace));
}
}
if(metricUri.metricName!=null) {
if(metricUri.metricName.indexOf('%')!=-1) {
criteria.add(Restrictions.like("name", metricUri.metricName));
} else {
criteria.add(Restrictions.eq("name", metricUri.metricName));
}
}
if(metricUri.metricType!=null && metricUri.metricType.length>0) {
Set<Short> types = new HashSet<Short>(metricUri.metricType.length);
for(int i : metricUri.metricType) {
types.add((short)i);
}
criteria.add(Restrictions.in("t.typeId", types));
}
if(metricUri.metricStatus!=null && metricUri.metricStatus.length>0) {
Set<Byte> statuses = new HashSet<Byte>(metricUri.metricStatus.length);
for(int i : metricUri.metricStatus) {
statuses.add((byte)i);
}
criteria.add(Restrictions.in("state", statuses));
}
return criteria;
}
/**
* Generates a SQL statement for retrieving the metric Ids that are in the result set for the passed MetricURI
* @param metricUri The MetricURI
* @return the SQL statement
* FIXME: Replace literals with bind variables
*/
protected static String generateCriteriaSQL(MetricURI metricUri) {
StringBuilder sql = new StringBuilder("SELECT METRIC_ID FROM METRIC M, AGENT A, HOST H WHERE M.AGENT_ID = A.AGENT_ID AND A.HOST_ID = H.HOST_ID ");
if(!"%".equals(metricUri.domain)) {
sql.append(metricUri.domain.indexOf('%')==-1 ?
"AND H.DOMAIN = '" + metricUri.domain + "' "
:
"AND H.DOMAIN LIKE '" + metricUri.domain + "' ");
}
if(!"%".equals(metricUri.host)) {
sql.append(metricUri.host.indexOf('%')==-1 ?
"AND H.NAME = '" + metricUri.host + "' "
:
"AND H.NAME LIKE '" + metricUri.host + "' ");
}
if(!"%".equals(metricUri.agent)) {
sql.append(metricUri.agent.indexOf('%')==-1 ?
"AND A.NAME = '" + metricUri.agent + "' "
:
"AND A.NAME LIKE '" + metricUri.agent + "' ");
}
if(metricUri.maxDepth>0) {
sql.append(" AND (M.NAMESPACE LIKE '").append(metricUri.namespace).append("%").append("'")
.append(" AND M.LEVEL <= ").append(metricUri.maxDepth).append(") ");
} else {
if(metricUri.namespace.indexOf('%')!=-1) {
sql.append(" AND M.NAMESPACE LIKE '").append(metricUri.namespace).append("' ");
} else {
sql.append(" AND M.NAMESPACE = '").append(metricUri.namespace).append("' ");
}
}
if(metricUri.metricName!=null) {
if(metricUri.metricName.indexOf('%')!=-1) {
sql.append(" AND M.NAME LIKE '").append(metricUri.metricName).append("' ");
} else {
sql.append(" AND M.NAME = '").append(metricUri.metricName).append("' ");
}
}
if(metricUri.metricType!=null && metricUri.metricType.length>0) {
Set<Short> types = new HashSet<Short>(metricUri.metricType.length);
for(int i : metricUri.metricType) {
types.add((short)i);
}
sql.append(" AND M.TYPE_ID IN (");
for(short typeId: types) {
sql.append(typeId).append(",");
}
sql.deleteCharAt(sql.length()-1);
sql.append(") ");
}
if(metricUri.metricStatus!=null && metricUri.metricStatus.length>0) {
Set<Byte> statuses = new HashSet<Byte>(metricUri.metricStatus.length);
for(int i : metricUri.metricStatus) {
statuses.add((byte)i);
}
sql.append(" AND M.STATE IN (");
for(byte status: statuses) {
sql.append(status).append(",");
}
sql.deleteCharAt(sql.length()-1);
sql.append(") ");
}
LOG.info("Generated SQL for Metric IDs [\n\t" + sql + "\n\t]");
return sql.toString();
}
/**
* Returns the detached criteria for this MetricURI
* @return the detached criteria
*/
public DetachedCriteria getDetachedCriteria() {
return this.detachedCriteria;
}
/**
* Executes the MetricURI's detached criteria and returns a list of matching metrics
* @param session A hibernate session to execute with
* @param timeout Set a timeout for the underlying JDBC query in seconds
* @return a list of matching metrics
*/
@SuppressWarnings("unchecked")
public List<Metric> execute(Session session, int timeout) {
return detachedCriteria.getExecutableCriteria(session).setTimeout(timeout).list();
}
/**
* Executes the MetricURI's detached criteria and returns a list of matching metrics with no timeout
* @param session A hibernate session to execute with
* @return a list of matching metrics
*/
@SuppressWarnings("unchecked")
public List<Metric> execute(Session session) {
return detachedCriteria.getExecutableCriteria(session).list();
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.dataservice.json.catalog.MetricURIMBean#getMetricUri()
*/
@Override
public String getMetricUri() {
return metricUri.toString();
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.dataservice.json.catalog.MetricURIMBean#getDomain()
*/
@Override
public String getDomain() {
return domain;
}
/**
* Returns the metric host
* @return the metric host
*/
public String getHost() {
return host;
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.dataservice.json.catalog.MetricURIMBean#getAgent()
*/
@Override
public String getAgent() {
return agent;
}
/**
* Returns the metric namespace
* @return the metric namespace
*/
public String getNamespace() {
return namespace;
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.dataservice.json.catalog.MetricURIMBean#getMaxDepth()
*/
@Override
public int getMaxDepth() {
return maxDepth;
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.dataservice.json.catalog.MetricURIMBean#getMetricName()
*/
@Override
public String getMetricName() {
return metricName;
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.dataservice.json.catalog.MetricURIMBean#getMetricType()
*/
@Override
public int[] getMetricType() {
return metricType;
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.dataservice.json.catalog.MetricURIMBean#getMetricTypeNames()
*/
@Override
public String[] getMetricTypeNames() {
String[] arr = new String[metricType.length];
for(int i = 0; i < metricType.length; i++) {
arr[i] = MetricType.valueOf(metricType[i]).name();
}
return arr;
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.dataservice.json.catalog.MetricURIMBean#getMetricStatus()
*/
@Override
public byte[] getMetricStatus() {
return metricStatus;
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.dataservice.json.catalog.MetricURIMBean#getMetricStatusNames()
*/
@Override
public String[] getMetricStatusNames() {
String[] arr = new String[metricStatus.length];
for(int i = 0; i < metricStatus.length; i++) {
arr[i] = EntryStatus.decode(metricStatus[i]);
}
return arr;
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.dataservice.json.catalog.MetricURIMBean#getMetricIdSql()
*/
@Override
public String getMetricIdSql() {
return metricIdSql;
}
/**
* Returns the mask of the enabled metric types
* @return the metricTypeMask
*/
public int getMetricTypeMask() {
return metricTypeMask;
}
/**
* Returns the mask of the enabled metric statuses
* @return the metricStatusMask
*/
public int getMetricStatusMask() {
return metricStatusMask;
}
/**
* Returns the combined bit mask of the bit masks for metric type, metric status and subscription type.
* @return the combined bit mask of the bit masks for metric type, metric status and subscription type.
*/
public long getMetricTypeStatusSubTypeMask() {
return metricTypeStatusSubTypeMask;
}
}
interface PerformanceMetadataMBean {
double getTimeTook();
void setTimeTook(double timeTook);
String getRequestType();
void setRequestType(String requestType);
}
class RequestPerformanceMetadata implements PerformanceMetadataMBean {
private double startTime;
private double endTime;
private double timeTook;
private String requestType;
private int numOfRequests;
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name;
public RequestPerformanceMetadata() {
try {
name = new ObjectName("test.performace:type=PerformanceMetadataMBean");
} catch (Exception ex) {
throw new RuntimeException("Yo dog. Bad object name", ex);
}
}
public double getTimeTook() {
return timeTook;
}
public void setTimeTook(double timeTook) {
this.timeTook = timeTook;
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.dataservice.json.catalog.PerformanceMetadataMBean#getRequestType()
*/
@Override
public String getRequestType() {
// TODO Auto-generated method stub
return null;
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.dataservice.json.catalog.PerformanceMetadataMBean#setRequestType(java.lang.String)
*/
@Override
public void setRequestType(String requestType) {
// TODO Auto-generated method stub
}
}