/* * * Copyright (c) void.fm * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * Neither the name void.fm nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ package etm.contrib.integration.spring.configuration; import etm.contrib.aggregation.log.CommonsLoggingAggregator; import etm.contrib.aggregation.log.Jdk14LogAggregator; import etm.contrib.aggregation.log.Log4jAggregator; import etm.core.aggregation.BufferedThresholdAggregator; import etm.core.aggregation.BufferedTimedAggregator; import etm.core.aggregation.NotifyingAggregator; import etm.core.aggregation.RootAggregator; import etm.core.aggregation.persistence.FileSystemPersistenceBackend; import etm.core.aggregation.persistence.PersistentRootAggregator; import etm.core.configuration.EtmMonitorFactory; import etm.core.jmx.EtmMonitorJmxPlugin; import etm.core.timer.DefaultTimer; import org.springframework.beans.FatalBeanException; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * BeanDefinitionParser that parses a JETM runtime element. * * @author $Id$ * @version $Revision$ * @since 1.2.0 */ public class RuntimeBeanDefinitionParser extends JetmBeanDefinitionParser { protected AbstractBeanDefinition parseInternal(Element aElement, ParserContext aParserContext) { String type = aElement.getAttribute("type"); String timer = aElement.getAttribute("timer"); Element features = DomUtils.getChildElementByTagName(aElement, "features"); Element aggregatorChain = DomUtils.getChildElementByTagName(aElement, "aggregator-chain"); Element extension = DomUtils.getChildElementByTagName(aElement, "extension"); if (type == null || type.length() == 0) { type = "nested"; } BeanDefinitionBuilder builder; if ("nested".equals(type)) { builder = BeanDefinitionBuilder.rootBeanDefinition(etm.core.monitor.NestedMonitor.class); } else if ("flat".equals(type)) { builder = BeanDefinitionBuilder.rootBeanDefinition(etm.core.monitor.FlatMonitor.class); } else { try { builder = BeanDefinitionBuilder.rootBeanDefinition(Class.forName(type)); } catch (ClassNotFoundException e) { throw new FatalBeanException("Unable to locate monitor class " + type, e); } } if (timer != null && timer.length() > 0) { addTimerDefinition(timer, builder); } if (features != null) { buildChainFromFeatures(builder, features); } else if (aggregatorChain != null) { buildChainFromChain(builder, aggregatorChain); } if (extension != null) { if (features != null) { addExtensions(builder, extension, DomUtils.getChildElementByTagName(features, "jmx")); } else { addExtensions(builder, extension, null); } } builder.setInitMethodName("start"); builder.setDestroyMethodName("stop"); return builder.getBeanDefinition(); } private void addExtensions(BeanDefinitionBuilder aBuilder, Element aExtension, Element jmx) { List pluginConfigs = DomUtils.getChildElementsByTagName(aExtension, "plugin"); if (!pluginConfigs.isEmpty()) { List plugins = new ArrayList(); for (int i = 0; i < pluginConfigs.size(); i++) { Element element = (Element) pluginConfigs.get(i); String clazz = element.getAttribute("class"); BeanDefinitionBuilder builder; try { builder = BeanDefinitionBuilder.rootBeanDefinition(Class.forName(clazz)); } catch (ClassNotFoundException e) { throw new FatalBeanException("Unable to locate plugin class " + clazz, e); } List properties = DomUtils.getChildElementsByTagName(element, "property"); if (!properties.isEmpty()) { for (int j = 0; j < properties.size(); j++) { Element aProperty = (Element) properties.get(j); addProperty(builder, aProperty); } } plugins.add(builder.getBeanDefinition()); } ManagedList list = new ManagedList(plugins.size()); list.addAll(plugins); if (jmx != null) { String monitorObjectName = jmx.getAttribute("monitorObjectName"); String mbeanServerName = jmx.getAttribute("mbeanServerName"); String measurementDomain = jmx.getAttribute("measurementDomain"); String overwrite = jmx.getAttribute("overwrite"); BeanDefinitionBuilder jmxBuilder = BeanDefinitionBuilder.rootBeanDefinition(EtmMonitorJmxPlugin.class); if (monitorObjectName != null && monitorObjectName.length() > 0) { jmxBuilder.addPropertyValue("monitorObjectName", monitorObjectName); } if (mbeanServerName != null && mbeanServerName.length() > 0) { jmxBuilder.addPropertyValue("mbeanServerName", mbeanServerName); } if (measurementDomain != null && measurementDomain.length() > 0) { jmxBuilder.addPropertyValue("measurementDomain", measurementDomain); } if (overwrite != null && overwrite.length() > 0) { jmxBuilder.addPropertyValue("overwrite", overwrite); } list.add(jmxBuilder.getBeanDefinition()); } aBuilder.addPropertyValue("plugins", list); } } private void buildChainFromChain(BeanDefinitionBuilder aBuilder, Element aAggregatorChain) { List chainElements = DomUtils.getChildElementsByTagName(aAggregatorChain, "chain-element"); Element chainRoot = DomUtils.getChildElementByTagName(aAggregatorChain, "chain-root"); BeanDefinitionBuilder chainBuilder; Class rootClazz; if (chainRoot != null) { String rootClassName = chainRoot.getAttribute("class"); try { rootClazz = Class.forName(rootClassName); } catch (ClassNotFoundException e) { throw new FatalBeanException("Unable to locate chain root class " + rootClassName, e); } } else { rootClazz = RootAggregator.class; } chainBuilder = BeanDefinitionBuilder.rootBeanDefinition(rootClazz); if (!chainElements.isEmpty()) { for (int i = chainElements.size() - 1; i >= 0; i--) { Element chainElement = (Element) chainElements.get(i); String chainClassName = chainElement.getAttribute("class"); BeanDefinitionBuilder nestedBuilder; try { nestedBuilder = BeanDefinitionBuilder.rootBeanDefinition(Class.forName(chainClassName)); } catch (ClassNotFoundException e) { throw new FatalBeanException("Unable to locate chain element class " + chainClassName, e); } List propertyElements = DomUtils.getChildElementsByTagName(chainElement, "property"); if (!propertyElements.isEmpty()) { for (int j = 0; j < propertyElements.size(); j++) { Element property = (Element) propertyElements.get(j); addProperty(nestedBuilder, property); } } nestedBuilder.addConstructorArg(chainBuilder.getBeanDefinition()); chainBuilder = nestedBuilder; } } // register our chain aBuilder.addConstructorArg(chainBuilder.getBeanDefinition()); } private void buildChainFromFeatures(BeanDefinitionBuilder runtimeBuilder, Element aElement) { Element thresholdBufferElement = DomUtils.getChildElementByTagName(aElement, "threshold-buffer"); Element intervalBuffer = DomUtils.getChildElementByTagName(aElement, "interval-buffer"); Element notifications = DomUtils.getChildElementByTagName(aElement, "notifications"); Element rawDataLog = DomUtils.getChildElementByTagName(aElement, "raw-data-log"); Element persistence = DomUtils.getChildElementByTagName(aElement, "persistence"); BeanDefinitionBuilder notificationBuilder = null; BeanDefinitionBuilder bufferBuilder; BeanDefinitionBuilder rawDataBuilder = null; BeanDefinitionBuilder aggregationRootBuilder; if (notifications != null) { notificationBuilder = BeanDefinitionBuilder.rootBeanDefinition(NotifyingAggregator.class); String rootOnly = notifications.getAttribute("rootOnly"); String filterPattern = notifications.getAttribute("filter-pattern"); if ("true".equals(rootOnly)) { notificationBuilder.addPropertyValue("rootOnly", "true"); } if (filterPattern != null && filterPattern.length() > 0) { notificationBuilder.addPropertyValue("filterPattern", filterPattern); } } if (persistence != null) { aggregationRootBuilder = BeanDefinitionBuilder.rootBeanDefinition(PersistentRootAggregator.class); Element fileBackend = DomUtils.getChildElementByTagName(persistence, "file-backend"); Element genericBackend = DomUtils.getChildElementByTagName(persistence, "custom-backend"); BeanDefinitionBuilder backendBuilder; if (fileBackend != null) { backendBuilder = BeanDefinitionBuilder.rootBeanDefinition(FileSystemPersistenceBackend.class); String file = fileBackend.getAttribute("filename"); String path = fileBackend.getAttribute("path"); if (file != null && file.length() > 0) { backendBuilder.addPropertyValue("filename", file); } if (path != null && path.length() > 0) { backendBuilder.addPropertyValue("path", path); } } else if (genericBackend != null) { String className = genericBackend.getAttribute("class"); try { backendBuilder = BeanDefinitionBuilder.rootBeanDefinition(Class.forName(className)); } catch (ClassNotFoundException e) { throw new FatalBeanException("Unable to locate persistence backend class " + className, e); } List properties = DomUtils.getChildElementsByTagName(genericBackend, "property"); for (Iterator iterator = properties.iterator(); iterator.hasNext();) { Element element = (Element) iterator.next(); addProperty(backendBuilder, element); } } else { backendBuilder = BeanDefinitionBuilder.rootBeanDefinition(FileSystemPersistenceBackend.class); } aggregationRootBuilder.addPropertyValue("persistenceBackend", backendBuilder.getBeanDefinition()); } else { aggregationRootBuilder = BeanDefinitionBuilder.rootBeanDefinition(RootAggregator.class); } if (rawDataLog != null) { String logType = rawDataLog.getAttribute("type"); String logCategory = rawDataLog.getAttribute("category"); String logFormaterClass = rawDataLog.getAttribute("formatter-class"); String filterPattern = rawDataLog.getAttribute("filter-pattern"); if ("log4j".equals(logType)) { rawDataBuilder = BeanDefinitionBuilder.rootBeanDefinition(Log4jAggregator.class); } else if ("commons".equals(logType)) { rawDataBuilder = BeanDefinitionBuilder.rootBeanDefinition(CommonsLoggingAggregator.class); } else if ("jdk14".equals(logType)) { rawDataBuilder = BeanDefinitionBuilder.rootBeanDefinition(Jdk14LogAggregator.class); } else { throw new BeanDefinitionStoreException("Raw logging type '" + logType + "' not supported"); } if (logCategory != null && logCategory.length() > 0) { rawDataBuilder.addPropertyValue("logName", logCategory); } if (filterPattern != null && filterPattern.length() > 0) { rawDataBuilder.addPropertyValue("filterPattern", filterPattern); } if (logFormaterClass != null && logFormaterClass.length() > 0) { RootBeanDefinition definition = new RootBeanDefinition(); definition.setBeanClassName(logFormaterClass); rawDataBuilder.addPropertyValue("formatter", definition); } } if (thresholdBufferElement != null) { bufferBuilder = BeanDefinitionBuilder.rootBeanDefinition(BufferedThresholdAggregator.class); String threshold = thresholdBufferElement.getAttribute("threshold"); if (threshold != null && threshold.length() > 0) { bufferBuilder.addPropertyValue("threshold", threshold); } } else if (intervalBuffer != null) { bufferBuilder = BeanDefinitionBuilder.rootBeanDefinition(BufferedTimedAggregator.class); String interval = intervalBuffer.getAttribute("threshold"); if (interval != null && interval.length() > 0) { bufferBuilder.addPropertyValue("interval", interval); } } else { bufferBuilder = BeanDefinitionBuilder.rootBeanDefinition(BufferedThresholdAggregator.class); } // now build up chain - reverse BeanDefinitionBuilder chainBuilder = aggregationRootBuilder; if (rawDataBuilder != null) { rawDataBuilder.addConstructorArg(chainBuilder.getBeanDefinition()); chainBuilder = rawDataBuilder; } if (notificationBuilder != null) { notificationBuilder.addConstructorArg(chainBuilder.getBeanDefinition()); chainBuilder = notificationBuilder; } bufferBuilder.addConstructorArg(chainBuilder.getBeanDefinition()); chainBuilder = bufferBuilder; runtimeBuilder.addConstructorArg(chainBuilder.getBeanDefinition()); } private void addProperty(BeanDefinitionBuilder builder, Element aElement) { String name = aElement.getAttribute("name"); String ref = aElement.getAttribute("ref"); if (ref != null && ref.length() > 0) { builder.addPropertyReference(name, ref); } else { builder.addPropertyValue(name, DomUtils.getTextValue(aElement)); } } private void addTimerDefinition(String aTimer, BeanDefinitionBuilder builder) { if ("jdk15".equals(aTimer)) { try { Class clazz = Class.forName("etm.core.timer.Java15NanoTimer"); builder.addConstructorArg(clazz.newInstance()); } catch (Exception e) { throw new FatalBeanException("Java15NanoTimer is not available for this platform. Please try 'sun' or " + "'default' instead.", e); } } else if ("sun".equals(aTimer)) { try { Class clazz = Class.forName("etm.core.timer.SunHighResTimer. Please try 'jdk15' or 'default' instead."); builder.addConstructorArg(clazz.newInstance()); } catch (Exception e) { throw new FatalBeanException("SunHighResTimer is not available for this platform.", e); } } else if ("default".equals(aTimer)) { builder.addConstructorArg(new DefaultTimer()); } else if ("bestAvailable".equals(aTimer)) { builder.addConstructorArg(EtmMonitorFactory.bestAvailableTimer()); } else { RootBeanDefinition timerBeanDefinition = new RootBeanDefinition(); timerBeanDefinition.setBeanClassName(aTimer); builder.addConstructorArg(timerBeanDefinition); } } }