org.fuin.srcgen4j.commons.SrcGen4J.java Source code

Java tutorial

Introduction

Here is the source code for org.fuin.srcgen4j.commons.SrcGen4J.java

Source

/**
 * Copyright (C) 2013 Future Invent Informationsmanagement GmbH. All rights
 * reserved. <http://www.fuin.org/>
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option) any
 * later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library. If not, see <http://www.gnu.org/licenses/>.
 */
package org.fuin.srcgen4j.commons;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.validation.constraints.NotNull;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.OrFileFilter;
import org.apache.commons.io.filefilter.RegexFileFilter;
import org.fuin.objects4j.common.Contract;
import org.fuin.objects4j.common.NeverNull;
import org.fuin.utils4j.Utils4J;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Parses models based on a configuration and generates something with it.
 */
public final class SrcGen4J {

    private static final Logger LOG = LoggerFactory.getLogger(SrcGen4J.class);

    private final SrcGen4JConfig config;

    private final SrcGen4JContext context;

    private FileFilter fileFilter;

    /**
     * Constructor with configuration.
     * 
     * @param config
     *            Initialized configuration (Method
     *            {@link SrcGen4JConfig#init(SrcGen4JContext, File)} was at
     *            least called once before).
     * @param context
     *            Build context.
     */
    public SrcGen4J(@NotNull final SrcGen4JConfig config, @NotNull final SrcGen4JContext context) {
        super();
        Contract.requireArgNotNull("config", config);
        Contract.requireArgNotNull("context", context);
        if (!config.isInitialized()) {
            throw new IllegalArgumentException("The configuration is not initialized");
        }
        this.config = config;
        this.context = context;
    }

    private void enhanceClasspath() {
        final Classpath cp = config.getClasspath();
        if (cp == null) {
            LOG.debug("No additional classpath found");
        } else {

            // Add context class path
            if (cp.isAddContextCP()) {
                addToClasspath(context.getJarFiles(), "Context jar files");
                addToClasspath(context.getBinDirs(), "Context bin directories");
            }

            // Add class paths from configuration
            final List<BinClasspathEntry> binList = cp.getBinList();
            if (binList == null) {
                LOG.debug("No binary classpath list found");
            } else {
                for (final BinClasspathEntry entry : binList) {
                    final String url;
                    if (entry.getPath().startsWith("file:")) {
                        url = entry.getPath();
                    } else {
                        url = "file:///" + entry.getPath();
                    }
                    LOG.info("Adding to classpath: " + url);
                    Utils4J.addToClasspath(url, context.getClassLoader());
                }
            }
        }
    }

    private void addToClasspath(final List<File> files, final String message) {
        if (files.size() == 0) {
            LOG.debug("No files found (" + message + ")");
        } else {
            for (final File file : files) {
                LOG.info("Adding to classpath (" + message + "): " + file);
                Utils4J.addToClasspath(file, context.getClassLoader());
            }
        }
    }

    private void cleanFolders() {
        final List<Project> projects = config.getProjects();
        if ((projects == null) || (projects.size() == 0)) {
            LOG.warn("No projects configured!");
        } else {
            for (final Project project : projects) {
                final List<Folder> folders = project.getFolders();
                if ((folders == null) || (folders.size() == 0)) {
                    LOG.warn("No project folders configured for: " + project.getName());
                } else {
                    for (final Folder folder : folders) {
                        final File dir = folder.getCanonicalDir();
                        if (folder.isClean() && dir.exists()) {
                            LOG.info("Cleaning: " + dir);
                            cleanDirectory(dir, folder);
                        } else {
                            LOG.debug("Nothing to to [clean=" + folder.isClean() + ", exists=" + dir.exists()
                                    + "]: " + dir);
                        }
                    }
                }
            }
        }
    }

    private boolean cleanDirectory(final File dir, final Folder folder) {

        File[] files = dir.listFiles();
        if (files == null) {
            return true;
        }
        for (final File file : files) {
            if (folder.cleanAllowed(file)) {
                if (file.isDirectory()) {
                    if (cleanDirectory(file, folder)) {
                        delete(file);
                    }
                } else {
                    delete(file);
                }
            } else {
                LOG.info("Excluded from cleaning: " + file);
            }
        }
        files = dir.listFiles();
        final boolean empty = (files == null || files.length == 0);
        if (!empty) {
            LOG.debug("Directory still contains " + files.length + " files after cleaning");
        }
        return empty;
    }

    private void delete(final File file) {
        final boolean ok = file.delete();
        if (!ok) {
            if (file.isDirectory()) {
                LOG.error("Couldn't delete directory: " + file);
            } else {
                LOG.error("Couldn't delete file: " + file);
            }
        }
    }

    /**
     * Parse and generate.
     * 
     * @throws ParseException
     *             Error during parse process.
     * @throws GenerateException
     *             Error during generation process.
     */
    public final void execute() throws ParseException, GenerateException {

        LOG.info("Executing full build");

        enhanceClasspath();

        cleanFolders();

        // Parse models & generate
        final Parsers parsers = config.getParsers();
        if (parsers == null) {
            LOG.warn("No parsers element");
        } else {
            final List<ParserConfig> parserConfigs = parsers.getList();
            if (parserConfigs == null) {
                LOG.warn("No parsers configured");
            } else {
                for (final ParserConfig pc : parserConfigs) {
                    final Parser<Object> parser = pc.getParser();
                    final Object model = parser.parse();
                    final List<GeneratorConfig> generatorConfigs = config.findGeneratorsForParser(pc.getName());
                    for (final GeneratorConfig gc : generatorConfigs) {
                        final Generator<Object> generator = gc.getGenerator();
                        generator.generate(model, false);
                    }
                }
            }
        }

    }

    /**
     * Returns a file filter that combines all filters for all incremental
     * parsers. It should be used for selecting the appropriate files.
     * 
     * @return File filter.
     */
    @NeverNull
    public FileFilter getFileFilter() {
        if (fileFilter == null) {
            final List<IOFileFilter> filters = new ArrayList<IOFileFilter>();
            final Parsers parsers = config.getParsers();
            if (parsers != null) {
                final List<ParserConfig> parserConfigs = parsers.getList();
                if (parserConfigs != null) {
                    for (final ParserConfig pc : parserConfigs) {
                        final Parser<Object> pars = pc.getParser();
                        if (pars instanceof IncrementalParser) {
                            final IncrementalParser<?> parser = (IncrementalParser<?>) pars;
                            filters.add(parser.getFileFilter());
                        }
                    }
                }
            }
            fileFilter = new OrFileFilter(filters);
        }
        return fileFilter;
    }

    /**
     * Incremental parse and generate. The class loader of this class will be
     * used.
     * 
     * @param files
     *            Set of files to parse for the model.
     * 
     * @throws ParseException
     *             Error during parse process.
     * @throws GenerateException
     *             Error during generation process.
     */
    public final void execute(@NotNull final Set<File> files) throws ParseException, GenerateException {

        Contract.requireArgNotNull("files", files);

        LOG.info("Executing incremental build (" + files.size() + " files)");
        if (LOG.isDebugEnabled()) {
            for (final File file : files) {
                LOG.debug(file.toString());
            }
        }

        if (files.size() == 0) {
            // Nothing to do...
            return;
        }

        // Parse models & generate
        final Parsers parsers = config.getParsers();
        if (parsers == null) {
            LOG.warn("No parsers element");
        } else {
            final List<ParserConfig> parserConfigs = parsers.getList();
            if (parserConfigs == null) {
                LOG.warn("No parsers configured");
            } else {
                for (final ParserConfig pc : parserConfigs) {
                    final Parser<Object> pars = pc.getParser();
                    if (pars instanceof IncrementalParser) {
                        final IncrementalParser<?> parser = (IncrementalParser<?>) pars;
                        final Object model = parser.parse(files);
                        final List<GeneratorConfig> generatorConfigs = config.findGeneratorsForParser(pc.getName());
                        for (final GeneratorConfig gc : generatorConfigs) {
                            final Generator<Object> generator = gc.getGenerator();
                            generator.generate(model, true);
                        }
                    } else {
                        LOG.debug("No incremental parser: " + pars.getClass().getName());
                    }
                }
            }
        }

    }

}