/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * 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 * * http://www.apache.org/licenses/LICENSE-2.0 *******************************************************************************/ package org.ebayopensource.turmeric.runtime.common.impl.internal.monitoring; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.xml.namespace.QName; import org.ebayopensource.turmeric.runtime.binding.utils.BindingUtils; import org.ebayopensource.turmeric.runtime.common.exceptions.ErrorDataFactory; import org.ebayopensource.turmeric.runtime.common.exceptions.ServiceException; import org.ebayopensource.turmeric.runtime.common.impl.internal.service.BaseServiceDescFactory; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricDef; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricId; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricsRegistry; import org.ebayopensource.turmeric.runtime.errorlibrary.ErrorConstants; import com.ebay.kernel.initialization.InitializationException; /** * @author wdeng * @author ichernyshev */ final class MetricsRegistryImpl extends MetricsRegistry { private final boolean m_isClientSide; private MetricsCollectorImpl m_collector; private List<MetricDef> m_metricDefs = new ArrayList<MetricDef>(); private MetricsRegistryImpl(boolean isClientSide) { m_isClientSide = isClientSide; } static void createClientInstance() { MetricsRegistryImpl result = createRegistryInstance(true); setClientInstance(result); MetricsCollectorImpl.setClientInstance(result.m_collector); } static void createServerInstance() { MetricsRegistryImpl result = createRegistryInstance(false); setServerInstance(result); MetricsCollectorImpl.setServerInstance(result.m_collector); } static MetricsRegistryImpl createRegistryInstance(boolean isClientSide) { MetricsRegistryImpl registry = new MetricsRegistryImpl(isClientSide); MetricsCollectorImpl collector = new MetricsCollectorImpl(registry); registry.m_collector = collector; return registry; } boolean isClientSide() { return m_isClientSide; } /** * RegisterMetric is expected to be called at init time */ @Override public void registerMetrics(List<MetricDef> metricDefs) throws ServiceException { for (MetricDef def: metricDefs) { registerMetric(def); } } /** * The registerMetric method register the MetricDefinitions. * The MetricId can contain wildcard in its serviceName, * operationName, and/or usecaseName to indicate an apply-all. * or null to indicate don't-care. * * registerMetric is expected to be called at init time. */ @Override public synchronized void registerMetric(MetricDef metricDef) throws ServiceException { boolean alreadyRegistered = validateMetricDef(metricDef); if (alreadyRegistered) { return; } m_metricDefs.add(metricDef); } @Override public List<MetricDef> unregisterMetricsByDef(List<MetricDef> metricDefs) { ArrayList<MetricDef> result = new ArrayList<MetricDef>(metricDefs.size()); for (MetricDef def: metricDefs) { MetricDef def2 = unregisterMetricByDef(def); if (def2 != null) { result.add(def2); } } return result; } @Override public MetricDef unregisterMetricByDef(MetricDef metricDef) { return unregisterMetric(metricDef.getMetricName(), metricDef.getServiceName(), metricDef.getOperationName()); } /** * What is the behavior when some of the classifiers are wild card or null? */ @Override public MetricDef unregisterMetric(String metricName, QName serviceName, String operationName) { MetricDef def = null; synchronized (this) { for (Iterator<MetricDef> it=m_metricDefs.iterator(); it.hasNext();) { MetricDef def2 = it.next(); if (!def2.getMetricName().equals(metricName) || !def2.getServiceName().equals(serviceName) || !BindingUtils.sameObject(def2.getOperationName(), operationName)) { continue; } it.remove(); def = def2; break; } } if (def != null) { m_collector.removeMetricValues(def); } return def; } /** * Check if the metricDef is registered. If the metricDef has conflict with * existing metricDef, throws ServiceException. * * Returns the existing registered MetricDef that contains the given * MetricDef. */ private boolean validateMetricDef(MetricDef newDef) throws ServiceException { MetricDef overlappingDef = null; boolean result = false; for (MetricDef def: m_metricDefs) { if (!def.getMetricName().equals(newDef.getMetricName())) { // different name, ignoring continue; } if (def.equals(newDef)) { // equivalent redefinition, ignore result = true; continue; } QName svcName = def.getServiceName(); QName newSvcName = newDef.getServiceName(); if (MetricDef.SVC_APPLY_TO_ALL.equals(svcName) || MetricDef.SVC_APPLY_TO_ALL.equals(newSvcName) || svcName.equals(newSvcName)) { // service names would overlap overlappingDef = def; break; } String opName = def.getOperationName(); String newOpName = newDef.getOperationName(); if (opName == MetricDef.OP_DONT_CARE || opName.equals(MetricDef.OP_APPLY_TO_ALL) || newOpName == MetricDef.OP_DONT_CARE || newOpName.equals(MetricDef.OP_APPLY_TO_ALL) || opName.equals(newOpName)) { // operation names would overlap overlappingDef = def; break; } } if (overlappingDef != null) { throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_METRICS_DEFINITION_CONFLICT, ErrorConstants.ERRORDOMAIN, new Object[] {newDef.toString(), overlappingDef.toString()})); } return result; } /** * Gets the MetricDef for the given MetricId. * If the definition don't exist in the registry but the id * is included in a definition with wildcards, A new * MetricDef will be created, registered and return. * * @param metricId A metric id without any wildcard and/or don't-care */ @Override public synchronized MetricDef findMetricDef(MetricId metricId) { for (MetricDef def: m_metricDefs) { if (matchDef(def, metricId)) { return def; } } return null; } /** * otherId is contained if it is the same as this or this is a * wildcard id that contains otherId. */ private boolean matchDef(MetricDef def, MetricId id) { if (!def.getMetricName().equals(id.getMetricName())) { // metric name must be the same. return false; } QName svcName = def.getServiceName(); if (!MetricDef.SVC_APPLY_TO_ALL.equals(svcName)) { BaseServiceDescFactory serviceFactory; if (m_isClientSide) { serviceFactory = BaseServiceDescFactory.getClientInstance(); } else { serviceFactory = BaseServiceDescFactory.getServerInstance(); } QName idQName = serviceFactory.findKnownQNameByAdminName(id.getAdminName()); if (idQName == null || !svcName.equals(idQName)) { // we accept only specific service name and it's not a match return false; } } String defOpName = def.getOperationName(); if (defOpName == MetricDef.OP_DONT_CARE || defOpName.equals(MetricDef.OP_APPLY_TO_ALL)) { return true; } String opName = id.getOperationName(); return (opName != null && defOpName.equals(opName)); } /** * Registers all the MetricDefs defined in a class as public static * and final constants. */ @Override public void registerAllMetricsForClass(Class clazz) { try { Field[] fields = clazz.getFields(); for (int i=0; i<fields.length; i++) { Field field = fields[i]; int modifier = field.getModifiers(); if (!MetricDef.class.isAssignableFrom(field.getType()) || !Modifier.isFinal(modifier) || !Modifier.isStatic(modifier) || !Modifier.isPublic(modifier)) { continue; } MetricDef def = (MetricDef)field.get(null); if (def != null) { registerMetric(def); } } } catch (SecurityException e) { throw new InitializationException(e); } catch (IllegalAccessException e) { throw new InitializationException(e); } catch (ServiceException e) { throw new InitializationException(e); } } }