org.opoo.press.impl.ConfigImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.opoo.press.impl.ConfigImpl.java

Source

/*
 * Copyright 2014 Alex Lin.
 *
 * 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 org.opoo.press.impl;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.opoo.press.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Alex Lin
 * @since 1.2
 */
public class ConfigImpl extends HashMap<String, Object> implements Config {
    private static final long serialVersionUID = 2347499217663917623L;
    private static final Logger log = LoggerFactory.getLogger(ConfigImpl.class);

    public static final String DEFAULT_NEW_POST_TEMPLATE = "new_post.ftl";
    public static final String DEFAULT_NEW_PAGE_TEMPLATE = "new_page.ftl";

    public static final String DEFAULT_POSTS_FOLDER = "posts";
    public static final String DEFAULT_PAGES_FOLDER = "pages";
    public static final String DEFAULT_ASSETS_FOLDER = "assets";
    public static final String DEFAULT_NEW_POST_FILE = "posts/${year}-${month}-${day}-${name}.${format}";
    public static final String DEFAULT_NEW_PAGE_FILE = "pages/${name}.${format}";
    public static final String DEFAULT_PERMALINK_STYLE = "/article/${year}/${month}/${name}.html";

    public static final FileFilter DEFAULT_CONFIG_FILES_FILTER = new DefaultConfigFilesFilter();

    private static ObjectMapper objectMapper;
    private Map<String, Object> overrideConfig;
    private File[] configFiles;
    private final File base;
    private boolean useDefaultConfigFiles = false;

    /**
     * Construct configuration instance.
     * 
     * @param base Base directory of this site. 
     *       Call {@link File#getCanonicalFile()} first.
     * @param override Options override.
     */
    public ConfigImpl(File base, Map<String, Object> override) {
        this.base = base;

        //default config
        initDefaultConfig();

        //override config
        if (override != null) {
            putAll(override);
            this.overrideConfig = override;
        }

        //config files
        long start = System.currentTimeMillis();
        this.configFiles = resolveConfigFiles(base, override);
        Arrays.sort(configFiles, new ConfigFileComparator());
        loadConfigFromFiles(configFiles);
        log.debug("Config files loaded in {} ms.", (System.currentTimeMillis() - start));
    }

    private void initDefaultConfig() {
        put("opoopress", defaultOpooPressOptions());

        put("root", "");
        put("asset_dirs", Arrays.asList(DEFAULT_ASSETS_FOLDER));
        put("source_dirs", Arrays.asList(DEFAULT_PAGES_FOLDER, DEFAULT_POSTS_FOLDER));
        put("plugin_dir", "plugins");
        put("dest_dir", "target/public");
        put("work_dir", "target/work");

        put("permalink", DEFAULT_PERMALINK_STYLE);
        put("permalink_label", "&infin;");

        //      put("new_post", DEFAULT_NEW_POST_FILE);
        //      put("new_page", DEFAULT_NEW_PAGE_FILE);

        put("category_dir", "/category");
        //put("category_names", new HashMap<String,String>());
        put("tag_dir", "/tag");

        put("excerpt_separator", "<!--more-->");

        put("paginate", 10);
        put("recent_posts", 5);
        put("related_posts", 5);
    }

    public static Map<String, Object> defaultOpooPressOptions() {
        Map<String, Object> options = new HashMap<String, Object>();
        Package pkg = ConfigImpl.class.getPackage();
        String version = pkg != null ? pkg.getSpecificationVersion() : null;
        if (StringUtils.isBlank(version)) {
            version = "unkown_version";
        }

        options.put("version", version);
        options.put("name", "OpooPress");
        return options;
    }

    private void loadConfigFromFiles(File[] configFiles) {
        for (File file : configFiles) {
            log.info("Loading config from {}", file);
            loadConfigFromFile(file);
        }
    }

    /**
     * @param file
     */
    @SuppressWarnings("unchecked")
    private void loadConfigFromFile(File file) {
        String name = file.getName();

        InputStream inputStream = null;
        Map<String, Object> map = null;
        try {
            inputStream = FileUtils.openInputStream(file);
            if (FilenameUtils.isExtension(name, "json")) {
                if (objectMapper == null) {
                    objectMapper = new ObjectMapper();
                }
                map = objectMapper.readValue(inputStream, Map.class);
            } else {
                //yaml is not thread safe, so create new instance
                map = new Yaml().loadAs(inputStream, Map.class);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            IOUtils.closeQuietly(inputStream);
        }

        if (map != null) {
            log.debug("Config loaded: {}", map);
            putAll(map);
        }
    }

    /**
     * Find all configuration files.
     * @param base site base site
     * @param override  command options, system properties, etc.
     * @return
     */
    private File[] resolveConfigFiles(File base, Map<String, Object> override) {
        //system properties
        //-Dconfig=config.json -> override
        //Override
        if (override != null) {
            String configFilesString = (String) override.remove("config");
            if (StringUtils.isNotBlank(configFilesString)) {
                log.info("Using config files: {}", configFilesString);

                String[] strings = StringUtils.split(configFilesString, ',');
                File[] files = new File[strings.length];
                for (int i = 0; i < strings.length; i++) {
                    files[i] = new File(base, strings[i]);
                }
                return files;
            }
        }

        //default
        useDefaultConfigFiles = true;
        return base.listFiles(DEFAULT_CONFIG_FILES_FILTER);
    }

    Map<String, Object> getOverrideConfig() {
        return overrideConfig;
    }

    /* (non-Javadoc)
     * @see org.opoo.press.Config#getConfigFiles()
     */
    @Override
    public File[] getConfigFiles() {
        return configFiles;
    }

    /* (non-Javadoc)
     * @see org.opoo.press.Config#get(java.lang.String)
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> T get(String name) {
        return (T) super.get(name);
    }

    /* (non-Javadoc)
     * @see org.opoo.press.Config#get(java.lang.String, java.lang.Object)
     */
    @Override
    public <T> T get(String name, T defaultValue) {
        if (!containsKey(name)) {
            return defaultValue;
        }
        return get(name);
    }

    public File getBasedir() {
        return base;
    }

    /* (non-Javadoc)
     * @see org.opoo.press.Config#useDefaultConfigFiles()
     */
    @Override
    public boolean useDefaultConfigFiles() {
        return useDefaultConfigFiles;
    }

    private static class DefaultConfigFilesFilter implements FileFilter {
        static final String[] ACCEPTABLE_EXTENSIONS = new String[] { "yml", "yaml", "json" };

        /* (non-Javadoc)
         * @see java.io.FileFilter#accept(java.io.File)
         */
        @Override
        public boolean accept(File file) {
            String name = file.getName();
            return FilenameUtils.getBaseName(name).startsWith("config")
                    && FilenameUtils.isExtension(name, ACCEPTABLE_EXTENSIONS) && file.canRead();
        }
    }

    public static class ConfigFileComparator implements Comparator<File> {
        @Override
        public int compare(File o1, File o2) {
            String name1 = o1.getName();
            String name2 = o2.getName();
            if (name1.equals(name2)) {
                return 0;
            }

            int delta = getIndex(name1) - getIndex(name2);
            if (delta != 0) {
                return delta;
            }

            name1 = FilenameUtils.removeExtension(name1);
            name2 = FilenameUtils.removeExtension(name2);
            return name1.compareTo(name2);
        }

        private int getIndex(String name) {
            if (name.endsWith(".yml")) {
                return 1;
            } else if (name.endsWith(".yaml")) {
                return 2;
            } else if (name.endsWith(".json")) {
                return 3;
            } else {
                return Integer.MAX_VALUE;
            }
        }
    }
}