/** * 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.catalog.domain; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.HashMap; import java.util.Set; import org.apache.log4j.Logger; import org.hibernate.Query; import org.hibernate.Session; import com.google.gson.annotations.Expose; /** * <p>Title: AgentMetricSet</p> * <p>Description: An optimization to retrieve a more structured JSON representation of the metrics for a specified agent</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.apmrouter.catalog.domain.AgentMetricSet</code></p> */ public class AgentMetricSet { /** Static class logger */ protected static final Logger LOG = Logger.getLogger(AgentMetricSet.class); /** The root level folders */ protected final Map<String, Folder> folders = new LinkedHashMap<String, Folder>(); /** The root level metrics */ protected final Set<Map<String, Map<String, Object>>> metrics = new LinkedHashSet<Map<String, Map<String, Object>>>(); /** The attribute property key for the ID */ public static final String FOLDER_TAG_ID = "id"; /** The attribute property key for the folder name */ public static final String FOLDER_TAG_FOLDER_NAME = "folder_name"; /** The attribute property key for the rel (metric tree node type) */ public static final String FOLDER_TAG_REL = "rel"; /** The attribute property key for the agent Id */ public static final String FOLDER_TAG_AGENT_ID = "agentid"; /** The data property key for the title */ public static final String FOLDER_TAG_TITLE = "title"; /** * Creates a new AgentMetricSet * @param session The hibernate session to query the metric tree * @param agentId The agent ID of the agent to get the metric tree for * @return an AgentMetricSet */ public static AgentMetricSet newInstance(Session session, int agentId) { LOG.info("Fetching AMS for agent [" + agentId + "]"); Query query = session.getNamedQuery("allMetricsForAgent"); query.setInteger("agentId", agentId); @SuppressWarnings("unchecked") List<Metric> metrics = query.list(); return new AgentMetricSet(metrics); } /** * Creates an indent of tabs * @param level The number of tabs * @return a char array of tabs */ public static char[] indent(int level) { char[] ind = new char[level]; Arrays.fill(ind, '\t'); return ind; } private AgentMetricSet(List<Metric> metrics) { LOG.info("Building AMS with [" + metrics.size() + "] Metrics"); for(Metric metric: metrics) { String[] narr = metric.getNarr(); int cnt = narr.length; if(cnt==0) { this.metrics.add(mapMetric(metric)); // zero level metric (no namespace) } else { Folder folder = folders.get(narr[0]); if(folder==null) { LOG.info(new StringBuilder("FOLDER ").append(narr[0])); folders.put(narr[0], new Folder(metric)); } else { folder.processMetric(metric); } } } } /** * Generates a metric tree friendly representation of a metric * @param metric The metric to render * @return the map of maps representing the metric */ protected static Map<String, Map<String, Object>> mapMetric(Metric metric) { Map<String, Map<String, Object>> map = new HashMap<String, Map<String, Object>>(2); Map<String, Object> attr = new HashMap<String, Object>(); Map<String, Object> data = new HashMap<String, Object>(); attr.put(FOLDER_TAG_ID, "metric-" + metric.getMetricId()); attr.put(FOLDER_TAG_FOLDER_NAME, metric.getName()); attr.put(FOLDER_TAG_REL, "metric"); data.put(FOLDER_TAG_TITLE, metric.getName()); map.put("attr", attr); map.put("data", data); return map; } /** * <p>Title: Folder</p> * <p>Description: Represents a notional folder within which a metric exists</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.apmrouter.catalog.domain.AgentMetricSet.Folder</code></p> */ public static class Folder { /** The host Id */ @Expose(serialize=false) private final int hostId; /** The agent Id */ @Expose(serialize=false) private final int agentId; /** Indicates if this folder has metrics directly in it */ @Expose(serialize=false) private boolean hasMetrics = false; /** The folders directly in this folder */ @Expose(serialize=false) protected final Map<String, Folder> folders = new LinkedHashMap<String, Folder>(); /** The metrics directly in this folder */ @Expose(serialize=false) protected final Set<Map<String, Map<String, Object>>> metrics = new LinkedHashSet<Map<String, Map<String, Object>>>(); /** Attribute properties */ protected final Map<String, Object> attr = new LinkedHashMap<String, Object>(); /** Data properties */ protected final Map<String, Object> data = new LinkedHashMap<String, Object>(); /* attr : { id: "folder-" + (metric[0].replace('/', '').replace('=', '-')), folder_name : metric[0], type : metric[1], rel: "folder", agentid : $(me).attr('agentid') }, data : {title: metric[0], id : $(me).attr('id') + metric[0]} public static final String FOLDER_TAG_ID = "id"; public static final String FOLDER_TAG_FOLDER_NAME = "folder_name"; public static final String FOLDER_TAG_REL = "rel"; public static final String FOLDER_TAG_AGENT_ID = "agentid"; public static final String FOLDER_TAG_TITLE = "title"; */ /** * Creates a new root Folder and hierarchy from a metric * @param metric The metric to create the folder tree from */ public Folder(Metric metric) { hostId = metric.getAgent().getHost().getHostId(); agentId = metric.getAgent().getAgentId(); attr.put(FOLDER_TAG_ID, String.format("host-%s-agent-%s-%s", hostId, agentId, metric.getNarr()[0].replace("/", "").replace('=', '_'))); attr.put(FOLDER_TAG_FOLDER_NAME, metric.getNarr()[0]); attr.put(FOLDER_TAG_REL, "folder"); attr.put(FOLDER_TAG_AGENT_ID, agentId); data.put(FOLDER_TAG_TITLE, metric.getNarr()[0].replace("/", "")); processMetric(metric); } /** * Processes the full hierarchy of the passed metric within this folder * @param metric The metric to process */ protected void processMetric(Metric metric) { String[] narr = metric.getNarr(); final int cnt = narr.length; Folder currentFolder = this; StringBuilder fNode = new StringBuilder(narr[0]); for(int i = 1; i < cnt; i++) { fNode.append("-").append(narr[i]); Folder newFolder = currentFolder.folders.get(narr[i]); if(newFolder==null) { newFolder = new Folder(hostId, agentId, narr[i], fNode.toString()); currentFolder.folders.put(narr[i], newFolder); LOG.info(new StringBuilder().append(indent(i)).append("FOLDER ").append(narr[i])); } currentFolder = newFolder; } LOG.info(new StringBuilder().append(indent(cnt)).append("METRIC ").append(metric.getName())); currentFolder.metrics.add(mapMetric(metric)); currentFolder.attr.put(FOLDER_TAG_REL, "metric-folder"); currentFolder.hasMetrics = true; } /** * Creates a new Folder * @param hostId The host ID * @param agentId The agent ID * @param localNode The local node name * @param fullNode The cummulative fully qualified node name */ private Folder(int hostId, int agentId, String localNode, String fullNode) { this.hostId = hostId; this.agentId = agentId; attr.put(FOLDER_TAG_ID, String.format("host-%s-agent-%s-%s", hostId, agentId, localNode.replace("/", "").replace('=', '_'))); attr.put(FOLDER_TAG_FOLDER_NAME, localNode); attr.put(FOLDER_TAG_REL, "folder"); attr.put(FOLDER_TAG_AGENT_ID, agentId); data.put(FOLDER_TAG_TITLE, localNode.replace("/", "")); } /** * Indicates if this folder has metrics directly in it * @return true if this folder has metrics directly in it, false otherwise */ public boolean isHasMetrics() { return hasMetrics; } /** * Returns the host id * @return the hostId */ public int getHostId() { return hostId; } /** * Returns the agent id * @return the agentId */ public int getAgentId() { return agentId; } } }