/******************************************************************************* * 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.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.namespace.QName; import org.ebayopensource.turmeric.runtime.common.impl.internal.service.BaseServiceDescFactory; import org.ebayopensource.turmeric.runtime.common.impl.utils.LogManager; import org.ebayopensource.turmeric.runtime.common.monitoring.MonitoringLevel; import org.ebayopensource.turmeric.runtime.common.types.SOAConstants; import com.ebay.kernel.bean.configuration.BaseConfigBean; import com.ebay.kernel.bean.configuration.BeanConfigCategoryInfo; import com.ebay.kernel.bean.configuration.BeanPropertyInfo; import com.ebay.kernel.bean.configuration.ConfigCategoryCreateException; import com.ebay.kernel.bean.configuration.DynamicBeanPropertyCreationException; import com.ebay.kernel.bean.configuration.DynamicConfigBean; import com.ebay.kernel.initialization.InitializationException; public class DynamicMonitoringChangeMgr implements PropertyChangeListener, VetoableChangeListener { private static final String CONFIG_CATEGORY_PREFIX = SOAConstants.CONFIG_BEAN_GROUP + ".monitoring."; private static final String DESC = "This config bean enables monitoring level of SOA services to be updated dynamically"; private static final String PROP_NAME_ACTION = "ACTION"; private final boolean m_isClientSide; private DynamicConfigBean m_configBean; private Map<String, MonitoringLevel> m_configData = new HashMap<String, MonitoringLevel>(); private static DynamicMonitoringChangeMgr s_clientInstance; private static DynamicMonitoringChangeMgr s_serverInstance; private DynamicMonitoringChangeMgr(boolean isClientSide) { m_isClientSide = isClientSide; initConfigBean(); } private static Logger m_logger = null; private static Logger getLogger() { if (null == m_logger) { m_logger = LogManager.getInstance(DynamicMonitoringChangeMgr.class); } return m_logger; } public static synchronized DynamicMonitoringChangeMgr getClientInstance() { if (s_clientInstance == null) { s_clientInstance = new DynamicMonitoringChangeMgr(true); } return s_clientInstance; } public static synchronized DynamicMonitoringChangeMgr getServerInstance() { if (s_serverInstance == null) { s_serverInstance = new DynamicMonitoringChangeMgr(false); } return s_serverInstance; } private void initConfigBean() { try { BeanConfigCategoryInfo category = BeanConfigCategoryInfo .createBeanConfigCategoryInfo( CONFIG_CATEGORY_PREFIX + (m_isClientSide ? "Client" : "Server"), null, SOAConstants.CONFIG_BEAN_GROUP, false, true, null, DESC, true); m_configBean = new DynamicConfigBean(category); m_configBean.setExternalMutable(); if (!m_configBean.hasProperty(PROP_NAME_ACTION)) { m_configBean.addProperty(PROP_NAME_ACTION, ""); } m_configBean.addPropertyChangeListener(this); m_configBean.addVetoableChangeListener(this); } catch (ConfigCategoryCreateException e) { getLogger().log(Level.SEVERE, "Failed to initialize config bean: " + e.toString()); throw new InitializationException(e); } catch (DynamicBeanPropertyCreationException e) { getLogger().log(Level.SEVERE, "Failed to initialize config bean: " + e.toString()); throw new InitializationException(e); } } public MonitoringLevel getMonitoringLevel(String adminName) { MonitoringLevel result = null; synchronized (m_configData) { result = m_configData.get(adminName); } return result; } /** * This method gets called when a bound property is changed. * * @param evt * A PropertyChangeEvent object describing the event source and * the property that has changed. */ public void propertyChange(PropertyChangeEvent evt) { BeanPropertyInfo info = BaseConfigBean.getBeanPropertyInfo(evt); String adminName = info.getName(); String value = (String) evt.getNewValue(); if (adminName.equals(PROP_NAME_ACTION)) { if (value == null || value.length() == 0 || "done".equalsIgnoreCase(value)) { return; } executeCommand(value); return; } // Do need to support setting a Monitoring Level for all services? // if (componentName.equalsIgnoreCase(ALL_COMPONENTS) == true) { try { parseServiceName(adminName, evt); } catch (Throwable e) { // exception is logged in veto already return; } MonitoringLevel level = MonitoringLevel.NORMAL; try { level = parseMonitoringLevel(value, adminName, evt); } catch (Throwable e) { // exception is logged in veto already return; } updateMonitoringLevel(adminName, level); } public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { BeanPropertyInfo info = BaseConfigBean.getBeanPropertyInfo(evt); String adminName = info.getName(); String value = (String) evt.getNewValue(); if (adminName.equals(PROP_NAME_ACTION)) { if (value == null || value.length() == 0 || "done".equalsIgnoreCase(value)) { return; } verifyCommand(value); return; } parseServiceName(adminName, evt); parseMonitoringLevel(value, adminName, evt); } private void verifyCommand(String value) { // TODO: verify action value } private void executeCommand(String value) { // perform action specified in VALUE if (value.startsWith("reset:")) { // TODO: get adminName after ":" and reset all data for that // admin name m_configBean.setPropertyValue(PROP_NAME_ACTION, "done"); } } private void updateMonitoringLevel(String adminName, MonitoringLevel level) { synchronized (m_configData) { MonitoringLevel cachedLevel = m_configData.get(adminName); if (cachedLevel != null && (cachedLevel.ordinal() == level.ordinal())) { return; } m_configData.put(adminName, level); } resetMonitoringLevel(adminName); } private void resetMonitoringLevel(String adminName) { MetricsConfigManager mcm = null; if (m_isClientSide) { mcm = MetricsConfigManager.getClientInstance(); } else { mcm = MetricsConfigManager.getServerInstance(); } mcm.resetMonitoringLevel(adminName); } private void parseServiceName(String adminName, PropertyChangeEvent evt) throws PropertyVetoException { BaseServiceDescFactory descFactory = null; if (m_isClientSide) { descFactory = BaseServiceDescFactory.getClientInstance(); } else { descFactory = BaseServiceDescFactory.getServerInstance(); } QName qName = descFactory.findKnownQNameByAdminName(adminName); if (qName == null) { throw new PropertyVetoException("Unknown admin name " + adminName, evt); } } private MonitoringLevel parseMonitoringLevel(String value, String adminName, PropertyChangeEvent evt) throws PropertyVetoException { try { return MonitoringLevel.valueOf(value.toUpperCase().trim()); } catch (Throwable e) { throw new PropertyVetoException("Invalid monitoring level: " + value + " for service " + adminName, evt); } } }