ee.ria.xroad.commonui.OptionalPartsConf.java Source code

Java tutorial

Introduction

Here is the source code for ee.ria.xroad.commonui.OptionalPartsConf.java

Source

/**
 * The MIT License
 * Copyright (c) 2015 Estonian Information System Authority (RIA), Population Register Centre (VRK)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package ee.ria.xroad.commonui;

import ee.ria.xroad.common.CodedException;
import ee.ria.xroad.common.ErrorCodes;
import ee.ria.xroad.common.conf.globalconf.ConfigurationConstants;
import lombok.Getter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.filefilter.RegexFileFilter;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;

/**
 * Encapsulates optional parts configuration of central server.
 */
@Slf4j
public class OptionalPartsConf {
    private static final String KEY_PART_FILE_NAME;
    private static final String KEY_CONTENT_IDENTIFIER;
    private static final String KEY_VALIDATION_PROGRAM;

    private static final List<String> RESERVED_FILE_NAMES;
    private static final List<String> RESERVED_CONTENT_IDENTIFIERS;

    static {
        KEY_PART_FILE_NAME = "file-name";
        KEY_CONTENT_IDENTIFIER = "content-identifier";
        KEY_VALIDATION_PROGRAM = "validation-program";

        RESERVED_FILE_NAMES = Arrays.asList(ConfigurationConstants.FILE_NAME_PRIVATE_PARAMETERS,
                ConfigurationConstants.FILE_NAME_SHARED_PARAMETERS);
        RESERVED_CONTENT_IDENTIFIERS = Arrays.asList(ConfigurationConstants.CONTENT_ID_PRIVATE_PARAMETERS,
                ConfigurationConstants.CONTENT_ID_SHARED_PARAMETERS);
    }

    private final Map<String, String> partFileNameToValidationProgram = new HashMap<>();
    private final Map<String, String> partFileNameToContentIdentifier = new HashMap<>();

    @Getter
    private final List<OptionalConfPart> allParts = new ArrayList<>();

    @Getter
    private final List<String> errors = new ArrayList<>();

    private final Set<String> existingPartFileNames = new HashSet<>();

    /**
     * Creates optional parts configuration.
     *
     * @param confDir - directory, where optional part files are in.
     * @throws IOException - when optional parts directory cannot be read.
     */
    public OptionalPartsConf(String confDir) throws IOException {
        File optionalPartsDir = new File(confDir);

        final String optionalPartsPath = optionalPartsDir.getAbsolutePath();

        if (!optionalPartsDir.isDirectory()) {
            log.warn("Optional configuration parts directory '{}' " + "either does not exist or is regular file",
                    optionalPartsPath);
            return;
        }

        log.debug("Getting optional conf parts from directory '{}'", confDir);

        File[] optionalPartFiles = optionalPartsDir.listFiles(getIniFileFilter());

        if (optionalPartFiles == null) {
            log.warn("Optional part files list in directory '{}' " + "cannot be fetched.", optionalPartsPath);
            return;
        }

        List<File> files = Arrays.asList(optionalPartFiles);

        files.forEach(this::processFile);
    }

    private FileFilter getIniFileFilter() {
        return new RegexFileFilter("^.+\\.ini$");
    }

    /**
     * Returns absolute path to validation program according to path file name.
     *
     * @param partFile - Simple name of the part file.
     * @return - absolute path to validation program.
     */
    public String getValidationProgram(String partFile) {
        String validationProgram = partFileNameToValidationProgram.get(partFile);

        log.debug("Validation program for part file '{}': '{}'", partFile, validationProgram);

        return validationProgram;
    }

    /**
     * Returns content identifier respective to path file name.
     *
     * @param partFile - simple name of the part file.
     * @return - content identifier respective to part file.
     */
    public String getContentIdentifier(String partFile) {
        String contentIdentifier = partFileNameToContentIdentifier.get(partFile);

        log.debug("Content identifier for part file '{}': '{}'", partFile, contentIdentifier);

        return contentIdentifier;
    }

    @SneakyThrows
    private void processFile(File confFile) {
        try {
            Properties props = new Properties();
            props.load(new FileInputStream(confFile));

            String partFileName = props.getProperty(KEY_PART_FILE_NAME);
            String contentId = props.getProperty(KEY_CONTENT_IDENTIFIER);

            if (!isFileContentWellFormed(partFileName, contentId)) {
                log.warn("Optional part configuration file '{}' is malformed, "
                        + "please inspect it for correctness.", confFile.getAbsolutePath());
                return;
            }

            String validationProgram = props.getProperty(KEY_VALIDATION_PROGRAM);

            validatePartFileName(partFileName);

            validateContentIdentifier(contentId);

            partFileNameToValidationProgram.put(partFileName, validationProgram);
            partFileNameToContentIdentifier.put(partFileName, contentId);

            allParts.add(new OptionalConfPart(partFileName, contentId));
        } catch (IOException e) {
            log.error("Loading optional parts from file '" + confFile.getAbsolutePath() + "' failed: {}",
                    e.getMessage(), e); // throwable as last object param should work as of SLF4J 1.6.0

            errors.add(e.getMessage());
        }
    }

    private boolean isFileContentWellFormed(String partFile, String contentId) {
        return !(StringUtils.isBlank(partFile) || StringUtils.isBlank(contentId));

    }

    private void validatePartFileName(String partFileName) {
        if (RESERVED_FILE_NAMES.contains(partFileName)) {
            throw new CodedException(ErrorCodes.X_MALFORMED_OPTIONAL_PARTS_CONF,
                    "Optional parts configuration contains reserved filename'" + partFileName + "'.");
        }

        if (!existingPartFileNames.add(partFileName)) {
            throw new CodedException(ErrorCodes.X_MALFORMED_OPTIONAL_PARTS_CONF,
                    "Part file name'" + partFileName + "' occurs more than "
                            + "once in optional parts configuration. " + "Part file names must be unique.");
        }
    }

    private void validateContentIdentifier(String contentId) {
        if (RESERVED_CONTENT_IDENTIFIERS.contains(contentId)) {
            throw new CodedException(ErrorCodes.X_MALFORMED_OPTIONAL_PARTS_CONF,
                    "Optional parts configuration contains reserved content " + "identifier'" + contentId + "'.");
        }
    }
}