com.emc.ecs.sync.config.ConfigUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.emc.ecs.sync.config.ConfigUtil.java

Source

/*
 * Copyright 2013-2016 EMC Corporation. 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.
 * A copy of the License is located at
 *
 * http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 * or in the "license" file accompanying this file. This file 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.emc.ecs.sync.config;

import com.emc.ecs.sync.config.annotation.FilterConfig;
import com.emc.ecs.sync.config.annotation.Option;
import com.emc.ecs.sync.config.annotation.StorageConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;

public final class ConfigUtil {
    public static final String XML_NAMESPACE = "http://www.emc.com/ecs/sync/model";

    private static final Logger log = LoggerFactory.getLogger(ConfigUtil.class);

    private static final Map<Class<?>, ConfigWrapper<?>> wrapperCache = new HashMap<>();

    private static ClassPathScanningCandidateComponentProvider storageScanner;
    private static ClassPathScanningCandidateComponentProvider filterScanner;

    static {
        storageScanner = new ClassPathScanningCandidateComponentProvider(false);
        storageScanner.addIncludeFilter(new AnnotationTypeFilter(StorageConfig.class));
        filterScanner = new ClassPathScanningCandidateComponentProvider(false);
        filterScanner.addIncludeFilter(new AnnotationTypeFilter(FilterConfig.class));
    }

    @SuppressWarnings("unchecked")
    public static synchronized <C> ConfigWrapper<C> wrapperFor(Class<C> targetClass) {
        ConfigWrapper<C> configWrapper = (ConfigWrapper<C>) wrapperCache.get(targetClass);
        if (configWrapper == null) {
            configWrapper = new ConfigWrapper<>(targetClass);
            wrapperCache.put(targetClass, configWrapper);
        }
        return configWrapper;
    }

    @SuppressWarnings("unchecked")
    public static <C> void parseUri(C configObject, String uri) {
        wrapperFor((Class<C>) configObject.getClass()).parseUri(configObject, uri);
    }

    @SuppressWarnings("unchecked")
    public static <C> String generateUri(C configObject) {
        return wrapperFor((Class<C>) configObject.getClass()).generateUri(configObject);
    }

    public static ConfigWrapper<?> storageConfigWrapperFor(String uri) {
        for (ConfigWrapper<?> wrapper : allStorageConfigWrappers()) {
            if (uri.startsWith(wrapper.getUriPrefix()))
                return wrapper;
        }
        throw new IllegalArgumentException("No storage config defined for URI " + uri);
    }

    public static ConfigWrapper<?> filterConfigWrapperFor(String cliName) {
        for (ConfigWrapper<?> wrapper : allFilterConfigWrappers()) {
            if (cliName.equals(wrapper.getCliName()))
                return wrapper;
        }
        throw new IllegalArgumentException("No filter config named " + cliName);
    }

    public static Iterable<ConfigWrapper<?>> allStorageConfigWrappers() {
        return new Iterable<ConfigWrapper<?>>() {
            @Override
            public Iterator<ConfigWrapper<?>> iterator() {
                return new WrapperIterator(storageScanner.findCandidateComponents("com.emc.ecs.sync").iterator());
            }
        };
    }

    public static Iterable<ConfigWrapper<?>> allFilterConfigWrappers() {
        return new Iterable<ConfigWrapper<?>>() {
            @Override
            public Iterator<ConfigWrapper<?>> iterator() {
                return new WrapperIterator(filterScanner.findCandidateComponents("com.emc.ecs.sync").iterator());
            }
        };
    }

    public static String hyphenate(String name) {
        StringBuilder hyphenated = new StringBuilder();
        for (char c : name.toCharArray()) {
            if (Character.isUpperCase(c) && hyphenated.length() > 0)
                hyphenated.append('-');
            hyphenated.append(Character.toLowerCase(c));
        }
        return hyphenated.toString();
    }

    public static String labelize(String name) {
        StringBuilder label = new StringBuilder();
        for (char c : name.toCharArray()) {
            if (Character.isUpperCase(c) && label.length() > 0)
                label.append(' ');
            label.append(label.length() == 0 ? Character.toUpperCase(c) : c);
        }
        return label.toString();
    }

    @SuppressWarnings("unchecked")
    public static <C> String summarize(C configObject) {
        return wrapperFor((Class<C>) configObject.getClass()).summarize(configObject);
    }

    public static void validate(Object configObject) {
        try {
            ConfigWrapper<?> wrapper = wrapperFor(configObject.getClass());
            for (String property : wrapper.propertyNames()) {
                ConfigPropertyWrapper propertyWrapper = wrapper.getPropertyWrapper(property);
                Object value = propertyWrapper.getDescriptor().getReadMethod().invoke(configObject);
                // check required
                if (propertyWrapper.isRequired() && value == null)
                    throw new ConfigurationException(
                            wrapper.getTargetClass().getSimpleName() + "." + property + " is required");
            }
        } catch (InvocationTargetException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * convert an annotated getter into a commons-cli Option
     */
    public static org.apache.commons.cli.Option cliOptionFromAnnotation(PropertyDescriptor descriptor,
            Option _option, String prefix) {
        org.apache.commons.cli.Option option = new org.apache.commons.cli.Option(null, _option.description());

        // required
        if (_option.required())
            option.setRequired(true);

        // long name
        String longName;
        if (_option.cliName().length() > 0) {
            longName = _option.cliName();
        } else {
            longName = hyphenate(descriptor.getName());
            if ((Boolean.class == descriptor.getPropertyType()
                    || "boolean".equals(descriptor.getPropertyType().getName())) && _option.cliInverted())
                longName = "no-" + longName;
        }
        if (prefix != null)
            longName = prefix + longName;
        option.setLongOpt(longName);

        // parameter[s]
        if (descriptor.getPropertyType().isArray()) {
            option.setArgs(org.apache.commons.cli.Option.UNLIMITED_VALUES);
        } else if (Boolean.class != descriptor.getPropertyType()
                && !"boolean".equals(descriptor.getPropertyType().getName())) {
            // non-booleans *must* have an argument
            option.setArgs(1);
        }
        if (option.hasArg()) {
            if (_option.valueHint().length() > 0)
                option.setArgName(_option.valueHint());
            else
                option.setArgName(option.getLongOpt());
        }

        return option;
    }

    public static String join(String[] parts) {
        if (parts == null || parts.length == 0)
            return null;
        StringBuilder joined = new StringBuilder();
        for (int i = 0; i < parts.length; i++) {
            joined.append(parts[i]);
            if (i < parts.length - 1)
                joined.append(",");
        }
        return joined.toString();
    }

    private ConfigUtil() {
    }

    private static class WrapperIterator implements Iterator<ConfigWrapper<?>> {
        private Iterator<BeanDefinition> definitionIterator;
        private ConfigWrapper<?> nextElement;

        public WrapperIterator(Iterator<BeanDefinition> definitionIterator) {
            this.definitionIterator = definitionIterator;
            findNext();
        }

        @Override
        public boolean hasNext() {
            return nextElement != null;
        }

        @Override
        public ConfigWrapper<?> next() {
            if (nextElement == null)
                throw new NoSuchElementException();
            ConfigWrapper<?> element = nextElement;
            findNext();
            return element;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException("this is a read-only iterator");
        }

        @SuppressWarnings("unchecked")
        private void findNext() {
            nextElement = null;
            while (definitionIterator.hasNext() && nextElement == null) {
                BeanDefinition beanDef = definitionIterator.next();
                try {
                    nextElement = wrapperFor(Class.forName(beanDef.getBeanClassName()));
                } catch (ClassNotFoundException e) {
                    log.warn("could not load plugin config " + beanDef.getBeanClassName(), e);
                } catch (UnsupportedClassVersionError e) {
                    log.warn("the plugin for " + beanDef.getBeanClassName()
                            + " is not supported in this version of java", e);
                }
            }
        }
    }
}