/******************************************************************************* * 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.sif.impl.internal.config; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; import java.util.logging.Level; import java.util.logging.Logger; import org.ebayopensource.turmeric.runtime.common.exceptions.ServiceException; import org.ebayopensource.turmeric.runtime.common.impl.utils.LogManager; import org.ebayopensource.turmeric.runtime.sif.impl.internal.service.ClientServiceDescFactory; import com.ebay.kernel.bean.configuration.DynamicConfigBean; import com.ebay.kernel.bean.configuration.PropertyChangeHistory; abstract public class ClientServiceConfigBeanListener implements VetoableChangeListener, PropertyChangeListener { protected ClientServiceConfigBean m_bean; protected DynamicConfigBean m_dynamicBean; // If the constructor is called with a DynamicConfigBean protected boolean m_isDynamic = false; // will be set to true by the dynamic constructor private static Logger m_logger = null; private static Logger getLogger() { if (null == m_logger) { m_logger = LogManager .getInstance(ClientServiceTransportConfigBeanListener.class); } return m_logger; } public ClientServiceConfigBeanListener(ClientServiceConfigBean bean) { m_bean = bean; } public ClientServiceConfigBeanListener(DynamicConfigBean bean) { m_dynamicBean = bean; m_isDynamic = true; } public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { ClientConfigManager configMgr = null; ClientConfigHolder configGolden = null; ClientConfigHolder config = null; final String adminName = getAdminName(); final String clientName = getClientName(); try { configMgr = ClientConfigManager.getInstance(); config = getConfigForUpdate(configMgr); configGolden = config.copy(); setValuesForVeto(config, evt); reloadServiceDesc(configMgr, config, adminName, clientName); } catch (PropertyVetoException e) { if (getLogger().isLoggable(Level.WARNING)) { String msg = "Failed to update config bean for admin.clientName=" + adminName + "." + clientName + ": " + e + (e.getMessage() == null ? "" : "('" + e.getMessage() + "')") + " "; getLogger().log(Level.WARNING, msg, e); } throw e; } catch (Throwable e) { String msg = null; if (getLogger().isLoggable(Level.WARNING)) { msg = "Failed to update config bean for admin.clientName=" + adminName + "." + clientName + ": " + e + (e.getMessage() == null ? "" : "('" + e.getMessage() + "')") + " "; getLogger().log(Level.WARNING, msg, e); } try { if (configGolden != null) { reloadServiceDesc(configMgr, configGolden, adminName, clientName); } } catch (ServiceException e1) { if (getLogger().isLoggable(Level.WARNING)) { getLogger().log(Level.WARNING, msg + ": " + e1.toString()); } } throw new PropertyVetoException(msg, evt); } } /** * Defines the client name of the bean; please override for dynamic subclasses. * * @return bean's client name. */ protected String getClientName() { if (!m_isDynamic) { return m_bean.getClientName(); } throw new IllegalStateException("Your dynamic bean listener doesn't override getAdminName()"); } /** * Defines the admin name of the bean; please override for dynamic subclasses. * * @return bean's admin name. */ protected String getAdminName() { if (!m_isDynamic) { return m_bean.getAdminName(); } throw new IllegalStateException("Your dynamic bean listener doesn't override getAdminName()"); } /** * Defines the env name for the served config bean. Override for dynamic bean listeners. * @return the env name */ protected String getEnvName() { if (!m_isDynamic) { return m_bean.getEnvName(); } throw new IllegalStateException("Your dynamic bean listener doesn't override getEnvName()"); } public void propertyChange(PropertyChangeEvent evt) { // TODO: how can we group multiple changes, so that we reload // ServiceDesc only once PropertyChangeHistory changeHistory = m_bean.createChangeHistory(evt); changeHistory.updateStart(); try { setValuesForUpdate(evt); changeHistory.updateSuccess(); } catch (Throwable e) { logFailure(changeHistory, e); throw new IllegalArgumentException(e.toString()); } } ClientConfigHolder getConfigForUpdate(ClientConfigManager configMgr) throws Exception { String adminName = getAdminName(); String clientName = getClientName(); String envName = getEnvName(); ClientConfigHolder configHolder = configMgr.getConfigForUpdate( adminName, clientName, envName); return configHolder; } void reloadServiceDesc(ClientConfigManager configMgr, ClientConfigHolder config, String adminName, String clientName) throws ServiceException { String envName = getEnvName(); configMgr.updateConfig(adminName, clientName, config); ClientServiceDescFactory descFactory = ClientServiceDescFactory .getInstance(); descFactory.reloadServiceDesc(adminName, clientName, envName); } void logFailure(PropertyChangeHistory changeHistory, Throwable e) { if (changeHistory != null) { changeHistory.updateFailed(e); } String msg = "Failed to update config bean for admin.clientName=" + getAdminName() + "." + getClientName() + " " + e.toString(); getLogger().log(Level.WARNING, msg); } public void validateBooleanValue(PropertyChangeEvent evt, String name, String value) throws PropertyVetoException { if (("true".equalsIgnoreCase(value)) || "false".equalsIgnoreCase(value)) { return; } String msg = "Encountered invalid boolean property.value=" + name + "." + value + " "; throw new PropertyVetoException(msg, evt); } public void validateIntegerValue(PropertyChangeEvent evt, String name, String value) throws PropertyVetoException { try { Integer.valueOf(value); } catch (NumberFormatException e) { String msg = "Encountered invalid numeric property.value=" + name + "." + value + " "; throw new PropertyVetoException(msg + e.toString(), evt); } } public void validateStringValue(PropertyChangeEvent evt, String name, Object value) throws PropertyVetoException { if (!(value instanceof String)) { String msg = "Property '" + name + "' has a " + (value == null ? "null value" : "value '" + value + "' of type " + value.getClass().getName()) + " "; throw new PropertyVetoException(msg, evt); } } protected abstract void setValuesForVeto(ClientConfigHolder configHolder, PropertyChangeEvent evt) throws PropertyVetoException; protected abstract void setValuesForUpdate(PropertyChangeEvent evt) throws Exception; }