/** * Copyright 2014 Netflix, Inc. * <p/> * 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 * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * 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 com.netflix.servo.jmx; import com.netflix.servo.tag.Tag; import com.netflix.servo.tag.TagList; import com.netflix.servo.util.Throwables; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import java.util.regex.Pattern; /** * A helper class that assists in building * {@link ObjectName}s given monitor {@link Tag}s * or {@link TagList}. The builder also sanitizes * all values to avoid invalid input. Any characters that are * not alphanumeric, a period, or hypen are considered invalid * and are remapped to underscores. */ final class ObjectNameBuilder { private static final Pattern INVALID_CHARS = Pattern.compile("[^a-zA-Z0-9_\\-\\.]"); private static final Logger LOG = LoggerFactory.getLogger(ObjectNameBuilder.class); /** * Sanitizes a value by replacing any character that is not alphanumeric, * a period, or hyphen with an underscore. * * @param value the value to sanitize * @return the sanitized value */ public static String sanitizeValue(String value) { return INVALID_CHARS.matcher(value).replaceAll("_"); } /** * Creates an {@link ObjectNameBuilder} given the JMX domain. * * @param domain the JMX domain * @return The ObjectNameBuilder */ public static ObjectNameBuilder forDomain(String domain) { return new ObjectNameBuilder(domain); } private final StringBuilder nameStrBuilder; private ObjectNameBuilder(String domain) { nameStrBuilder = new StringBuilder(sanitizeValue(domain)); nameStrBuilder.append(":"); } /** * Adds the {@link TagList} as {@link ObjectName} properties. * * @param tagList the tag list to add * @return This builder */ public ObjectNameBuilder addProperties(TagList tagList) { for (Tag tag : tagList) { addProperty(tag); } return this; } /** * Adds the {@link Tag} as a {@link ObjectName} property. * * @param tag the tag to add * @return This builder */ public ObjectNameBuilder addProperty(Tag tag) { return addProperty(tag.getKey(), tag.getValue()); } /** * Adds the key/value as a {@link ObjectName} property. * * @param key the key to add * @param value the value to add * @return This builder */ public ObjectNameBuilder addProperty(String key, String value) { nameStrBuilder.append(sanitizeValue(key)) .append('=') .append(sanitizeValue(value)).append(","); return this; } /** * Builds the {@link ObjectName} given the configuration. * * @return The created ObjectName */ public ObjectName build() { final String name = nameStrBuilder.substring(0, nameStrBuilder.length() - 1); try { return new ObjectName(name); } catch (MalformedObjectNameException e) { LOG.warn("Invalid ObjectName provided: " + name); throw Throwables.propagate(e); } } }