com.pandich.dropwizard.curator.refresh.Refresher.java Source code

Java tutorial

Introduction

Here is the source code for com.pandich.dropwizard.curator.refresh.Refresher.java

Source

/*
 * This file is part of dropwizard-curator.
 *
 * dropwizard-curator is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * dropwizard-curator is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with dropwizard-curator.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.pandich.dropwizard.curator.refresh;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import com.pandich.dropwizard.curator.ClassMember;
import com.pandich.dropwizard.curator.CuratorInject;
import com.pandich.dropwizard.curator.CuratorRoot;
import com.pandich.dropwizard.curator.CuratorRootConfiguration;
import com.pandich.dropwizard.curator.NodeValue;
import com.pandich.dropwizard.curator.PropertySources;
import com.pandich.dropwizard.curator.PropertySources.PropertySource;
import com.pandich.dropwizard.curator.mapper.CuratorMapper;
import io.dropwizard.jackson.Jackson;
import org.apache.commons.lang3.CharUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.framework.api.CuratorListener;
import org.apache.zookeeper.KeeperException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Member;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Map;

import static com.google.common.base.CaseFormat.LOWER_UNDERSCORE;
import static com.google.common.base.CaseFormat.UPPER_CAMEL;
import static com.pandich.dropwizard.curator.PropertySources.PropertySource.DROPWIZARD;
import static com.pandich.dropwizard.curator.PropertySources.PropertySource.ZOOKEEPER;
import static org.apache.commons.lang3.ArrayUtils.subarray;
import static org.apache.commons.lang3.ClassUtils.isAssignable;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.join;
import static org.apache.commons.lang3.StringUtils.lowerCase;
import static org.apache.commons.lang3.StringUtils.split;
import static org.apache.commons.lang3.StringUtils.startsWith;
import static org.apache.commons.lang3.StringUtils.strip;

abstract class Refresher<A extends AccessibleObject & Member> implements CuratorListener {

    private static final Logger log = LoggerFactory.getLogger(Refresher.class);
    private static final String PATH_DELIMITER = "/";
    private static final ObjectMapper objectMapper = Jackson.newObjectMapper();

    private static String getNodePath(final Class<?> clazz, final String name, final CuratorInject curatorInject) {

        final String path;

        if (startsWith(curatorInject.value(), PATH_DELIMITER)) {
            path = curatorInject.value();
        } else {
            final String rootPath;
            final CuratorRoot curatorRoot = clazz.getAnnotation(CuratorRoot.class);
            if (curatorRoot != null && !isBlank(curatorRoot.value())) {
                rootPath = curatorRoot.value();
            } else {
                final String underscoreClassName = UPPER_CAMEL.to(LOWER_UNDERSCORE, clazz.getSimpleName());
                final String[] pieces = split(underscoreClassName, "_");
                rootPath = join(subarray(pieces, 0, pieces.length - 1));
            }

            final String nodeSubPath = defaultIfBlank(curatorInject.value(), name);
            final String normalizedRootPath = strip(rootPath, PATH_DELIMITER);
            path = lowerCase(PATH_DELIMITER + normalizedRootPath + PATH_DELIMITER + nodeSubPath);
        }

        log.debug("path: {}.{}={}", new Object[] { clazz.getSimpleName(), name, path });
        return path;
    }

    protected final Map<String, ClassMember<? extends Member>> pathElements = Maps.newHashMap();

    protected final Map<Class<?>, CuratorMapper<?>> mappers;
    protected final PropertySources propertySources = new PropertySources();
    protected final CuratorFramework client;
    protected final CuratorRootConfiguration configuration;

    public Refresher(final Map<Class<?>, CuratorMapper<?>> mappers, final CuratorFramework client,
            final CuratorRootConfiguration configuration) {
        this.mappers = mappers;
        this.client = client;
        this.configuration = configuration;
    }

    public final void refresh(final Class<? extends CuratorRootConfiguration> configurationClass, final A element)
            throws Exception {
        final String name = element.getName();
        log.debug("element: {}.{}", configurationClass.getSimpleName(), name);

        final CuratorInject curatorInject = element.getAnnotation(CuratorInject.class);

        try {

            final NodeValue nodeValue = getNodeValue(configurationClass, name, curatorInject);
            if (nodeValue.isBlank()) {
                return;
            }

            final Object value = getValue(element, nodeValue);
            write(element, value);

            log.debug("element: {}.{}={}", new Object[] { configurationClass.getSimpleName(), name, value });

            register(configurationClass, element, ZOOKEEPER);

            final String path = nodeValue.getPath();
            final ClassMember<A> member = new ClassMember<>(configurationClass, element);
            this.pathElements.put(path, member);

        } catch (KeeperException.NoNodeException ignore) {
            register(configurationClass, element, DROPWIZARD);
        }

    }

    @Override
    public void eventReceived(final CuratorFramework eventClient, final CuratorEvent event) throws Exception {
        if (event == null) {
            return;
        }
        log.debug("event={}", event);
        log.info("event {} on {} ", event.getType().name(), event.getPath());
        final ClassMember<? extends Member> member = this.pathElements.get(event.getPath());
        if (member != null && event.getPath() != null) {
            refresh(member.getConfigurationClass(), castMember(member.getMember()));
        }
    }

    protected final Object getValue(final A element, final NodeValue nodeValue) {
        final String rawValue = nodeValue.getValue();

        final Class<?> clazz = getType(element);

        final CuratorMapper<?> mapper = this.mappers.get(clazz);
        if (mapper != null) {
            return mapper.readValueFroMString(rawValue);
        }

        if (isAssignable(clazz, String.class)) {
            return rawValue;
        }

        if (isAssignable(clazz, Boolean.class)) {
            return Boolean.valueOf(rawValue);
        }

        if (isAssignable(clazz, Character.class)) {
            return CharUtils.toChar(rawValue);
        }

        if (isAssignable(clazz, Byte.class)) {
            return Byte.valueOf(rawValue);
        }

        if (isAssignable(clazz, Short.class)) {
            return Short.valueOf(rawValue);
        }

        if (isAssignable(clazz, Integer.class)) {
            return Integer.valueOf(rawValue);
        }

        if (isAssignable(clazz, Long.class)) {
            return Long.valueOf(rawValue);
        }

        if (isAssignable(clazz, Float.class)) {
            return Float.valueOf(rawValue);
        }

        if (isAssignable(clazz, Double.class)) {
            return Double.valueOf(rawValue);
        }

        if (isAssignable(clazz, BigInteger.class)) {
            return new BigInteger(rawValue);
        }

        if (isAssignable(clazz, BigDecimal.class)) {
            return new BigDecimal(rawValue);
        }

        try {
            return objectMapper.readValue(rawValue, clazz);
        } catch (IOException e) {
            throw new RuntimeException("type '" + clazz.getName() + "' is not supported", e);
        }
    }

    protected final A castMember(final Object o) {
        if (o == null) {
            return null;
        }
        return doCastMember(o);
    }

    private NodeValue getNodeValue(final Class<?> clazz, final String name, final CuratorInject curatorInject)
            throws Exception {
        final String nodePath = getNodePath(clazz, name, curatorInject);
        final String nodeValue;
        if (curatorInject.refresh()) {
            nodeValue = new String(this.client.getData().watched().forPath(nodePath));
        } else {
            nodeValue = new String(this.client.getData().forPath(nodePath));
        }

        return new NodeValue(nodePath, nodeValue);
    }

    private void write(A element, Object value) throws ReflectiveOperationException {
        log.debug("write: {} <- {}", element.getName(), value);
        doWrite(element, value);
    }

    protected abstract A doCastMember(final Object o);

    protected abstract Class<?> getType(A element);

    protected abstract void doWrite(A element, Object value) throws ReflectiveOperationException;

    protected abstract void register(Class<? extends CuratorRootConfiguration> configurationClass, A element,
            PropertySource source);

}