/* * ContextFactory.java * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 org.apache.hadoop.metrics; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Properties; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.metrics.spi.NullContext; /** * Factory class for creating MetricsContext objects. To obtain an instance * of this class, use the static <code>getFactory()</code> method. */ @InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"}) @InterfaceStability.Evolving public class ContextFactory { private static final String PROPERTIES_FILE = "/hadoop-metrics.properties"; private static final String CONTEXT_CLASS_SUFFIX = ".class"; private static final String DEFAULT_CONTEXT_CLASSNAME = "org.apache.hadoop.metrics.spi.NullContext"; private static ContextFactory theFactory = null; private Map<String,Object> attributeMap = new HashMap<String,Object>(); private Map<String,MetricsContext> contextMap = new HashMap<String,MetricsContext>(); // Used only when contexts, or the ContextFactory itself, cannot be // created. private static Map<String,MetricsContext> nullContextMap = new HashMap<String,MetricsContext>(); /** Creates a new instance of ContextFactory */ protected ContextFactory() { } /** * Returns the value of the named attribute, or null if there is no * attribute of that name. * * @param attributeName the attribute name * @return the attribute value */ public Object getAttribute(String attributeName) { return attributeMap.get(attributeName); } /** * Returns the names of all the factory's attributes. * * @return the attribute names */ public String[] getAttributeNames() { String[] result = new String[attributeMap.size()]; int i = 0; // for (String attributeName : attributeMap.keySet()) { Iterator it = attributeMap.keySet().iterator(); while (it.hasNext()) { result[i++] = (String) it.next(); } return result; } /** * Sets the named factory attribute to the specified value, creating it * if it did not already exist. If the value is null, this is the same as * calling removeAttribute. * * @param attributeName the attribute name * @param value the new attribute value */ public void setAttribute(String attributeName, Object value) { attributeMap.put(attributeName, value); } /** * Removes the named attribute if it exists. * * @param attributeName the attribute name */ public void removeAttribute(String attributeName) { attributeMap.remove(attributeName); } /** * Returns the named MetricsContext instance, constructing it if necessary * using the factory's current configuration attributes. <p/> * * When constructing the instance, if the factory property * <i>contextName</i>.class</code> exists, * its value is taken to be the name of the class to instantiate. Otherwise, * the default is to create an instance of * <code>org.apache.hadoop.metrics.spi.NullContext</code>, which is a * dummy "no-op" context which will cause all metric data to be discarded. * * @param contextName the name of the context * @return the named MetricsContext */ public synchronized MetricsContext getContext(String refName, String contextName) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { MetricsContext metricsContext = contextMap.get(refName); if (metricsContext == null) { String classNameAttribute = refName + CONTEXT_CLASS_SUFFIX; String className = (String) getAttribute(classNameAttribute); if (className == null) { className = DEFAULT_CONTEXT_CLASSNAME; } Class contextClass = Class.forName(className); metricsContext = (MetricsContext) contextClass.newInstance(); metricsContext.init(contextName, this); contextMap.put(contextName, metricsContext); } return metricsContext; } public synchronized MetricsContext getContext(String contextName) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { return getContext(contextName, contextName); } /** * Returns all MetricsContexts built by this factory. */ public synchronized Collection<MetricsContext> getAllContexts() { // Make a copy to avoid race conditions with creating new contexts. return new ArrayList<MetricsContext>(contextMap.values()); } /** * Returns a "null" context - one which does nothing. */ public static synchronized MetricsContext getNullContext(String contextName) { MetricsContext nullContext = nullContextMap.get(contextName); if (nullContext == null) { nullContext = new NullContext(); nullContextMap.put(contextName, nullContext); } return nullContext; } /** * Returns the singleton ContextFactory instance, constructing it if * necessary. <p/> * * When the instance is constructed, this method checks if the file * <code>hadoop-metrics.properties</code> exists on the class path. If it * exists, it must be in the format defined by java.util.Properties, and all * the properties in the file are set as attributes on the newly created * ContextFactory instance. * * @return the singleton ContextFactory instance */ public static synchronized ContextFactory getFactory() throws IOException { if (theFactory == null) { theFactory = new ContextFactory(); theFactory.setAttributes(); } return theFactory; } private void setAttributes() throws IOException { InputStream is = getClass().getResourceAsStream(PROPERTIES_FILE); if (is != null) { try { Properties properties = new Properties(); properties.load(is); //for (Object propertyNameObj : properties.keySet()) { Iterator it = properties.keySet().iterator(); while (it.hasNext()) { String propertyName = (String) it.next(); String propertyValue = properties.getProperty(propertyName); setAttribute(propertyName, propertyValue); } } finally { is.close(); } } } }