com.ryantenney.metrics.spring.reporter.AbstractReporterElementParser.java Source code

Java tutorial

Introduction

Here is the source code for com.ryantenney.metrics.spring.reporter.AbstractReporterElementParser.java

Source

/*
 * Copyright 2012 Ryan W Tenney (http://ryan.10e.us)
 *            and Martello Technologies (http://martellotech.com)
 *
 * 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
 *
 * 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 com.ryantenney.metrics.spring.reporter;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

public abstract class AbstractReporterElementParser implements ReporterElementParser {

    protected static final String ID = "id";
    protected static final String TYPE = "type";
    protected static final String METRIC_REGISTRY_REF = "metric-registry";

    protected Class<?> getBeanClass() {
        return null;
    }

    protected String getBeanClassName() {
        return null;
    }

    protected void parseReporter(Element element, BeanDefinitionBuilder beanDefinitionBuilder) {
    }

    @Override
    public AbstractBeanDefinition parseReporter(Element element, ParserContext parserContext) {
        final BeanDefinitionBuilder beanDefBuilder;
        if (getBeanClass() != null) {
            beanDefBuilder = BeanDefinitionBuilder.rootBeanDefinition(getBeanClass());
        } else {
            beanDefBuilder = BeanDefinitionBuilder.rootBeanDefinition(getBeanClassName());
        }

        beanDefBuilder.setRole(BeanDefinition.ROLE_APPLICATION);
        beanDefBuilder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
        try {
            parseReporter(element, beanDefBuilder);
            addDefaultProperties(element, beanDefBuilder);
            return beanDefBuilder.getBeanDefinition();
        } catch (Exception ex) {
            parserContext.getReaderContext().error(ex.getMessage(), element, ex);
            return null;
        }
    }

    protected void addDefaultProperties(Element element, BeanDefinitionBuilder beanDefBuilder) {
        final Map<String, String> properties = new HashMap<String, String>();
        final NamedNodeMap attributes = element.getAttributes();
        for (int i = 0; i < attributes.getLength(); i++) {
            final Node attribute = attributes.item(i);
            final String name = attribute.getNodeName();
            if (name.equals(METRIC_REGISTRY_REF) || name.equals(ID) || name.equals(TYPE)) {
                continue;
            }
            properties.put(name, attribute.getNodeValue());
        }

        validate(properties);

        beanDefBuilder.addPropertyReference("metricRegistry", element.getAttribute(METRIC_REGISTRY_REF));
        beanDefBuilder.addPropertyValue("properties", properties);
    }

    protected void validate(Map<String, String> properties) {
        final ValidationContext validationContext = new ValidationContext(properties);
        try {
            validate(validationContext);
        } catch (ValidationException ex) {
            throw ex;
        } catch (Throwable ex) {
            validationContext.reject(ex.getMessage(), ex);
        }
    }

    protected void validate(ValidationContext validator) {
    }

    protected static class ValidationException extends RuntimeException {

        private static final long serialVersionUID = 6435244612757724933L;

        public ValidationException(String message) {
            super(message);
        }

        public ValidationException(String message, Throwable cause) {
            super(message, cause);
        }

    }

    protected static class ValidationContext {

        private String lastKey;
        private final Map<String, String> properties;
        private final Set<String> allowedProperties;

        public ValidationContext(Map<String, String> properties) {
            this.properties = properties;
            this.allowedProperties = new HashSet<String>();
        }

        protected boolean has(String key) {
            return properties.get(key) != null;
        }

        protected String get(String key) {
            this.lastKey = key;
            return properties.get(key);
        }

        protected void reject(String message) {
            reject(lastKey, message);
        }

        protected void reject(String message, Throwable cause) {
            reject(lastKey, message, cause);
        }

        protected void reject(String key, String message) {
            throw new ValidationException(errorMessage(key, message));
        }

        protected void reject(String key, String message, Throwable cause) {
            throw new ValidationException(errorMessage(key, message), cause);
        }

        protected String require(String key) {
            return require(key, null, null);
        }

        protected String require(String key, String pattern) {
            return require(key, pattern, null);
        }

        protected String require(String key, String pattern, String message) {
            final String value = get(key);
            if (!StringUtils.hasText(value)) {
                reject(key, message);
            }
            check(key, value, pattern, message);
            allowedProperties.add(key);
            return value;
        }

        protected boolean optional(String key) {
            return optional(key, null, null);
        }

        protected boolean optional(String key, String pattern) {
            return optional(key, pattern, null);
        }

        protected boolean optional(String key, String pattern, String message) {
            final String value = get(key);
            if (StringUtils.hasText(value)) {
                check(key, value, pattern, message);
                allowedProperties.add(key);
                return true;
            }
            return false;
        }

        protected void rejectUnmatchedProperties() {
            if (!allowedProperties.containsAll(properties.keySet())) {
                final Set<String> unmatchedProperties = new HashSet<String>(properties.keySet());
                unmatchedProperties.removeAll(allowedProperties);
                throw new ValidationException("Properties " + Arrays.toString(unmatchedProperties.toArray())
                        + " are not permitted on this element.");
            }
        }

        private String errorMessage(String key, String message) {
            return "Attribute '" + key + "'" + (message != null ? ": " + message : "");
        }

        private void check(String key, String value, String pattern, String message) {
            if (pattern != null && !value.matches(pattern)) {
                reject(key, message);
                return;
            }
        }

    }

}