org.commonjava.web.config.io.ConfigFileUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.commonjava.web.config.io.ConfigFileUtils.java

Source

/**
 * Copyright (C) 2011 John Casey (jdcasey@commonjava.org)
 *
 * 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.commonjava.web.config.io;

import org.apache.commons.io.IOUtils;
import org.codehaus.plexus.interpolation.InterpolationException;
import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
import org.codehaus.plexus.interpolation.StringSearchInterpolator;
import org.commonjava.web.config.ConfigurationException;

import static org.apache.commons.io.FileUtils.readLines;
import static org.apache.commons.lang.StringUtils.join;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class ConfigFileUtils {

    private static final String LS = System.getProperty("line.separator", "\n");

    private static final String INCLUDE_COMMAND = "Include ";

    private static final String VARIABLES_COMMAND = "Variables ";

    private static final String GLOB_BASE_PATTERN = "([^\\?\\*]+)[\\\\\\/]([\\*\\?]+.+)";

    private static final String GLOB_IDENTIFYING_PATTERN = ".*[\\?\\*].*";

    private ConfigFileUtils() {
    }

    public static InputStream readFileWithIncludes(final String path) throws IOException, ConfigurationException {
        return readFileWithIncludes(new File(path), null);
    }

    public static InputStream readFileWithIncludes(final String path, Properties props)
            throws IOException, ConfigurationException {
        return readFileWithIncludes(new File(path), props);
    }

    public static InputStream readFileWithIncludes(final File f) throws IOException, ConfigurationException {
        return readFileWithIncludes(f, null);
    }

    public static InputStream readFileWithIncludes(final File f, Properties props)
            throws IOException, ConfigurationException {
        final List<String> lines = readLinesWithIncludes(f, props, false);

        return new ByteArrayInputStream(join(lines, LS).getBytes());
    }

    public static List<String> readLinesWithIncludes(final File f) throws IOException, ConfigurationException {
        return readLinesWithIncludes(f, null, false);
    }

    public static List<String> readLinesWithIncludes(final File f, Properties props)
            throws IOException, ConfigurationException {
        return readLinesWithIncludes(f, props, false);
    }

    public static List<String> readLinesWithIncludes(final File f, Properties props, boolean ignoreVariables)
            throws IOException, ConfigurationException {
        Properties vars = new Properties();

        final List<String> lines = new ArrayList<String>();
        final File dir = f.getParentFile();
        for (final String line : readLines(f)) {
            if (line.startsWith(INCLUDE_COMMAND)) {
                final String glob = line.substring(INCLUDE_COMMAND.length());
                for (final File file : findMatching(dir, glob)) {
                    lines.addAll(readLinesWithIncludes(file, null, true));
                }
            } else if (!ignoreVariables && line.startsWith(VARIABLES_COMMAND)) {
                final String glob = line.substring(VARIABLES_COMMAND.length());
                InputStream fs = null;
                for (final File file : findMatching(dir, glob)) {
                    try {
                        fs = new FileInputStream(file);
                        vars.load(fs);
                    } finally {
                        IOUtils.closeQuietly(fs);
                        fs = null;
                    }
                }
            } else {
                lines.add(line);
            }
        }

        StringSearchInterpolator ssi = new StringSearchInterpolator();
        ssi.addValueSource(new PropertiesBasedValueSource(props));
        ssi.addValueSource(new PropertiesBasedValueSource(vars));
        ssi.addValueSource(new PropertiesBasedValueSource(System.getProperties()));

        List<String> result = new ArrayList<String>();
        for (String line : lines) {
            try {
                result.add(ssi.interpolate(line));
            } catch (InterpolationException e) {
                throw new ConfigurationException("Failed to resolve expressions in '%s'. Reason: %s", e, line,
                        e.getMessage());
            }
        }

        return result;
    }

    public static File[] findMatching(final File dir, String glob) throws IOException {
        if (!glob.matches(GLOB_IDENTIFYING_PATTERN)) {
            File f = new File(glob);
            if (!f.isAbsolute()) {
                f = new File(dir, glob);
            }

            return new File[] { f };
        }

        final Matcher m = Pattern.compile(GLOB_BASE_PATTERN).matcher(glob);
        String base = null;
        String pattern = null;
        if (m.matches()) {
            base = m.group(1);
            pattern = m.group(2);

            if (!new File(base).isAbsolute()) {
                base = new File(dir, base).getAbsolutePath();
            }
        } else {
            base = dir.getAbsolutePath();
            pattern = glob;
        }

        if (pattern.length() < 1) {
            return new File[] { new File(base).getCanonicalFile() };
        }

        final StringBuilder regex = new StringBuilder();
        for (int i = 0; i < pattern.length(); i++) {
            final char c = pattern.charAt(i);
            switch (c) {
            case '*': {
                if (i + 1 < pattern.length() && pattern.charAt(i + 1) == '*') {
                    regex.append(".+");
                    i++;
                } else {
                    regex.append("[^\\\\\\/]*");
                }
                break;
            }
            case '.': {
                regex.append("\\.");
                break;
            }
            case '?': {
                regex.append(".");
                break;
            }
            default: {
                regex.append(c);
            }
            }
        }

        final boolean dirsOnly = pattern.endsWith("/") || pattern.endsWith("\\");
        final String globRegex = regex.toString();
        final File bdir = new File(base).getCanonicalFile();
        final int bdirLen = bdir.getPath().length() + 1;

        final List<File> allFiles = listRecursively(bdir);
        for (final Iterator<File> it = allFiles.iterator(); it.hasNext();) {
            final File f = it.next();
            if (dirsOnly && !f.isDirectory()) {
                it.remove();
                continue;
            }

            final String sub = f.getAbsolutePath().substring(bdirLen);

            if (!sub.matches(globRegex)) {
                it.remove();
            }
        }

        return allFiles.toArray(new File[] {});
    }

    private static List<File> listRecursively(final File dir) throws IOException {
        final List<File> files = new ArrayList<File>();
        final File d = dir.getCanonicalFile();

        recurse(d, files);

        return files;
    }

    private static void recurse(final File dir, final List<File> files) throws IOException {
        if (!dir.isDirectory()) {
            return;
        }

        for (final String name : dir.list()) {
            final File f = new File(dir, name).getCanonicalFile();

            files.add(f);
            if (f.isDirectory()) {
                recurse(f, files);
            }
        }
    }

}