/** * 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.metric.catalog.heap; import org.helios.apmrouter.metric.IMetric; import org.helios.apmrouter.metric.MetricType; import org.helios.apmrouter.metric.catalog.IDelegateMetric; import org.helios.apmrouter.util.StringHelper; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static org.helios.apmrouter.util.Methods.nvl; /** * <p>Title: HeapICEMetric</p> * <p>Description: An {@link IDelegateMetric} implementation which is a simple pojo and stored in heap.</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.apmrouter.metric.catalog.heap.HeapICEMetric</code></p> */ public class HeapICEMetric implements IDelegateMetric { /** The host name */ protected final String host; /** The agent name */ protected final String agent; /** The metricId namespace */ protected final String[] namespace; /** The metricId name */ protected final String name; /** The metricId type */ protected final MetricType type; /** Indicates if this is a flat or mapped metricId name */ protected final boolean flat; /** The serialization token */ protected transient long token = -1; /** The byte size of the metricId, held until the token is received */ protected transient volatile int byteSize = -1; /** The unmapped instance of a mapped metric ID */ protected IDelegateMetric unmapped = null; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((agent == null) ? 0 : agent.hashCode()); result = prime * result + ((host == null) ? 0 : host.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + Arrays.hashCode(namespace); result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; HeapICEMetric other = (HeapICEMetric) obj; if (agent == null) { if (other.agent != null) return false; } else if (!agent.equals(other.agent)) return false; if (host == null) { if (other.host != null) return false; } else if (!host.equals(other.host)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (!Arrays.equals(namespace, other.namespace)) return false; if (type != other.type) return false; return true; } /** * {@inheritDoc} * @see java.lang.Object#toString() */ @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("HeapICEMetric [host="); builder.append(host); builder.append(", agent="); builder.append(agent); builder.append(", namespace="); builder.append(Arrays.toString(namespace)); builder.append(", name="); builder.append(name); builder.append(", type="); builder.append(type); builder.append("]"); return builder.toString(); } /** * Creates a new HeapICEMetric * @param host The host name * @param agent The agent name * @param name The metricId name * @param type The metricId type * @param namespace An optional array of namespace entries */ HeapICEMetric(String host, String agent, CharSequence name, MetricType type, CharSequence... namespace) { this.host = nvl(host, "Host Name"); this.agent = nvl(agent, "Agent Name"); this.name = nvl(name, "Metric Name").toString(); this.type = nvl(type, "Metric Type"); final List<String> ns = new ArrayList<String>(); this.flat = processNamespace(ns, namespace); this.namespace = ns.toArray(new String[ns.size()]); } /** * {@inheritDoc} * @see org.helios.apmrouter.metric.catalog.IDelegateMetric#unmap() * FIXME: All this stuff should be in a common abstract class */ public IDelegateMetric unmap() { if(!isMapped()) return this; if(unmapped==null) { String[] unmappedNamespace = new String[namespace.length]; for(int i = 0; i < namespace.length; i++) { int index = namespace[i].indexOf("="); unmappedNamespace[i] = index==-1 ? namespace[i] : namespace[i].substring(index+1); } unmapped = new HeapICEMetric(host, agent, name, type, unmappedNamespace); } return unmapped; } /** * Writes the supplied namespace into the passed string array list, validating and converting each namespace entry * @param ns The string array list to write to * @param namespace The namespace value * @return true if the namespace is flat, false if it is mapped */ private boolean processNamespace(final List<String> ns, CharSequence...namespace) { Boolean f = null; if(namespace==null || namespace.length<1) return true; int index = 0; for(CharSequence nms: namespace) { if(nms==null) continue; String s = nms.toString().trim(); if(s.isEmpty()) continue; if(s.indexOf(" ")!=-1) s.replace(" ", ""); int mindex = s.indexOf('='); if(f==null) { f = mindex==-1; if(f) { ns.add(s); } else { ns.add(validateMapped(s, mindex)); } } else { if(f) { if(mindex==-1) { ns.add(s); } else { ns.add(merge(s, mindex)); } } else { if(mindex==-1) { ns.add(String.format("ns%s=%s", index, s)); } else { ns.add(validateMapped(s, mindex)); } } } index++; } return f==null ? true : f; } /** * Merges a mapped namespace entry into a flat namespace. * If either the key or the value are empty, throws an exceptiom * @param ns The namespace to merge * @param index The index of the MDELIM * @return the merged namespace */ private String merge(String ns, int index) { return new StringBuilder(ns.substring(0, index)).append(ns.substring(index-1)).toString(); } /** * Validates a mapped namespace entry * If either the key or the value are empty, throws an exceptiom * @param ns The namespace to validate * @param index The index of the MDELIM * @return the validated string * @throws RuntimeException Thrown if the key or the value is empty */ private String validateMapped(String ns, int index) { if(ns.substring(0, index).isEmpty() || ns.substring(index-1).isEmpty()) { throw new RuntimeException("Mapped namespace entry [" + ns + "] had empty key or value", new Throwable()); } return ns; } /** * {@inheritDoc} * @see org.helios.apmrouter.metric.catalog.IDelegateMetric#getNamespaceF() */ public String getNamespaceF() { String[] ns = getNamespace(); if(ns.length==0) return ""; return StringHelper.fastConcatAndDelim(IMetric.NSDELIM, ns); } /** * {@inheritDoc} * @see org.helios.apmrouter.metric.catalog.IDelegateMetric#getFQN() */ public String getFQN() { return String.format(FQN_FORMAT, getHost(), getAgent(), getNamespaceF(), getName()); } /** * {@inheritDoc} * @see org.helios.apmrouter.metric.catalog.IDelegateMetric#getHost() */ @Override public String getHost() { return host; } /** * {@inheritDoc} * @see org.helios.apmrouter.metric.catalog.IDelegateMetric#getAgent() */ @Override public String getAgent() { return agent; } /** * {@inheritDoc} * @see org.helios.apmrouter.metric.catalog.IDelegateMetric#getName() */ @Override public String getName() { return name; } /** * {@inheritDoc} * @see org.helios.apmrouter.metric.catalog.IDelegateMetric#getNamespace() */ @Override public String[] getNamespace() { return namespace; } /** * {@inheritDoc} * @see org.helios.apmrouter.metric.catalog.IDelegateMetric#isFlat() */ @Override public boolean isFlat() { return flat; } /** * {@inheritDoc} * @see org.helios.apmrouter.metric.catalog.IDelegateMetric#isMapped() */ @Override public boolean isMapped() { return !flat; } /** * {@inheritDoc} * @see org.helios.apmrouter.metric.catalog.IDelegateMetric#getType() */ @Override public MetricType getType() { return type; } /** * Returns the serialization token for this IMetric * @return the serialization token for this IMetric or -1 if one has not been assigned */ @Override public long getToken() { return token; } /** * Sets the serialization token for this IMetric * @param token the serialization token for this IMetric */ @Override public void setToken(long token) { this.token = token; byteSize = -1; } /** * {@inheritDoc} * @see org.helios.apmrouter.metric.catalog.IDelegateMetric#getSerSize() */ @Override public int getSerSize() { if(getToken()!=-1) return 8; if(byteSize!=-1) return byteSize; byteSize = getFQN().getBytes().length + 4; // just the FQN and +4 for the int size . Type is serialized seperately return byteSize; } }