com.francetelecom.clara.cloud.logicalmodel.LogicalConfigServiceUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.francetelecom.clara.cloud.logicalmodel.LogicalConfigServiceUtils.java

Source

/**
 * Copyright (C) 2015 Orange
 * 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.francetelecom.clara.cloud.logicalmodel;

import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.PropertiesConfigurationLayout;

import com.francetelecom.clara.cloud.commons.BaseEqualsToStringObject;
import com.francetelecom.clara.cloud.commons.BusinessException;
import com.francetelecom.clara.cloud.commons.TechnicalException;
import com.francetelecom.clara.cloud.commons.ValidatorUtil;
import com.francetelecom.clara.cloud.logicalmodel.InvalidConfigServiceException.ErrorType;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.Sets;

/**
 * Utility class to help parsing and writing structured config content. It forbids duplicate keys or value lists.
 *
 * Unlike {@link org.apache.commons.configuration.PropertiesConfiguration} which behaves as "If a key is used more than once, the values are appended like if they were on the same line separated with commas.",
 * this class will throw exceptions in such cases.
 */
public class LogicalConfigServiceUtils implements Serializable {

    private static final long serialVersionUID = 6093491341610695862L;

    private static final Function<ConfigEntry, String> GET_KEY = new Function<ConfigEntry, String>() {
        @Override
        public String apply(ConfigEntry configEntry) {
            return configEntry.getKey();
        }
    };

    public String dumpConfigContentToString(StructuredLogicalConfigServiceContent content)
            throws InvalidConfigServiceException {
        StringWriter stringWriter = new StringWriter();
        dumpConfigContent(content, stringWriter);
        return stringWriter.toString();
    }

    public void dumpConfigContent(StructuredLogicalConfigServiceContent content, Writer writer)
            throws InvalidConfigServiceException {
        try {
            ValidatorUtil.validate(content);
        } catch (TechnicalException e) {
            throw new InvalidConfigServiceException("Invalid structured content:" + e, e);
        }
        PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration();
        PropertiesConfigurationLayout layout = propertiesConfiguration.getLayout();
        layout.setLineSeparator("\n");
        String headerComment = content.getHeaderComment();
        if (headerComment != null) {
            layout.setHeaderComment(headerComment);
        }
        for (ConfigEntry configEntry : content.configEntries) {
            String key = configEntry.getKey();
            propertiesConfiguration.addProperty(key, configEntry.getValue());
            String comment = configEntry.getComment();
            layout.setSeparator(key, "=");
            if (comment != null) {
                layout.setComment(key, comment);
            }
        }
        try {
            propertiesConfiguration.save(writer);
        } catch (ConfigurationException e) {
            throw new InvalidConfigServiceException("Invalid structured content or output:" + e, e);
        }
    }

    public StructuredLogicalConfigServiceContent parseConfigContent(String content)
            throws InvalidConfigServiceException {
        return parseConfigContent(new StringReader(content));
    }

    /**
     *
     *
     * @param reader
     * @return
     */
    public StructuredLogicalConfigServiceContent parseConfigContent(Reader reader)
            throws InvalidConfigServiceException {
        List<ConfigEntry> parsedEntries = new ArrayList<ConfigEntry>();
        PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration();

        try {
            propertiesConfiguration.load(reader);
        } catch (ConfigurationException e) {
            InvalidConfigServiceException invalidConfigServiceException = new InvalidConfigServiceException(
                    "Invalid config content. Caught:" + e, e);
            throw invalidConfigServiceException;
        }
        PropertiesConfigurationLayout layout = propertiesConfiguration.getLayout();
        String headerComment = layout.getHeaderComment();

        Set<String> keys = layout.getKeys();
        Set<String> duplicates = new HashSet<String>();
        for (String key : keys) {
            String comment = layout.getComment(key);
            if (comment != null) {
                comment = escapesPoundsInComments(comment);
            }
            if (!layout.isSingleLine(key)) {
                //reject the duplicate key
                duplicates.add(key);
            } else {
                String value = propertiesConfiguration.getString(key);
                parsedEntries.add(new ConfigEntry(key, value, comment));
            }
        }

        if (duplicates.size() > 0) {
            InvalidConfigServiceException invalidConfigServiceException = new InvalidConfigServiceException(
                    "Collisions! " + duplicates);
            invalidConfigServiceException.setType(ErrorType.DUPLICATE_KEYS);
            invalidConfigServiceException.getDuplicateKeys().addAll(duplicates);
            throw invalidConfigServiceException;
        }

        List<ConfigEntry> configEntries = parsedEntries;
        StructuredLogicalConfigServiceContent structuredLogicalConfigServiceContent = new StructuredLogicalConfigServiceContent(
                headerComment, configEntries);
        return structuredLogicalConfigServiceContent;
    }

    protected String escapesPoundsInComments(String rawComment) {
        return Pattern.compile("^[#!]", Pattern.MULTILINE).matcher(rawComment).replaceAll("");
    }

    /**
     * Provides structured typed access to a configuration string formatted in java.util.Properties format.
     */
    public static class StructuredLogicalConfigServiceContent extends BaseEqualsToStringObject
            implements Serializable {
        private static final long serialVersionUID = -3588073237349664245L;
        /**
         * Allows for null comment
         */
        private String headerComment;

        /**
         * Allows for empty list
         */
        @NotNull
        @Valid
        private List<ConfigEntry> configEntries;

        public StructuredLogicalConfigServiceContent(String headerComment, List<ConfigEntry> configEntries) {
            this.headerComment = headerComment;
            this.configEntries = configEntries;
        }

        public String getHeaderComment() {
            return headerComment;
        }

        public void setHeaderComment(String headerComment) {
            this.headerComment = headerComment;
        }

        public List<ConfigEntry> getConfigEntries() {
            return configEntries;
        }

        public void setConfigEntries(List<ConfigEntry> configEntries) {
            this.configEntries = configEntries;
        }

        public Collection<String> listKeys() {
            return Collections2.transform(configEntries, GET_KEY);
        }

    }

    /**
     * Represents individual entries in a a configuration string formatted in java.util.Properties format: comments, key, and value.
     */
    public static class ConfigEntry extends BaseEqualsToStringObject implements Serializable {
        private static final long serialVersionUID = 5371986407117742995L;
        /**
         * Allows for null comment
         */
        private String comment;
        @NotNull
        private String key;
        @NotNull
        private String value;

        public ConfigEntry(String key, String value, String comment) {
            this.comment = comment;
            this.key = key;
            this.value = value;
        }

        /**
         * Note that comments don't have a # or ! prefix
         * @return
         */
        public String getComment() {
            return comment;
        }

        /**
         * Assigns the comment
         * @param comment a single or multiline comment without # or ! prefix
         */
        public void setComment(String comment) {
            this.comment = comment;
        }

        public String getKey() {
            return key;
        }

        public void setKey(String key) {
            this.key = key;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }

    /**
     * Load a file from it's path, parse it's config content and return a Set of all keys from it.<br>
     * @param filePath
     * @return
     * @throws InvalidConfigServiceException
     */
    public Set<String> loadKeysFromFile(String filePath) throws InvalidConfigServiceException {
        InputStreamReader inputStreamReader = new InputStreamReader(
                this.getClass().getClassLoader().getResourceAsStream(filePath));
        StructuredLogicalConfigServiceContent releaseConfigContent = parseConfigContent(inputStreamReader);
        return Sets.newTreeSet(Collections2.transform(releaseConfigContent.getConfigEntries(), GET_KEY));
    }
}