com.cedarsoft.codegen.AbstractGenerator.java Source code

Java tutorial

Introduction

Here is the source code for com.cedarsoft.codegen.AbstractGenerator.java

Source

/**
 * Copyright (C) cedarsoft GmbH.
 *
 * Licensed under the GNU General Public License version 3 (the "License")
 * with Classpath Exception; you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *         http://www.cedarsoft.org/gpl3ce
 *         (GPL 3 with Classpath Exception)
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 3 only, as
 * published by the Free Software Foundation. cedarsoft GmbH designates this
 * particular file as subject to the "Classpath" exception as provided
 * by cedarsoft GmbH in the LICENSE file that accompanied this code.
 *
 * This code 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 General Public License
 * version 3 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 3 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact cedarsoft GmbH, 72810 Gomaringen, Germany,
 * or visit www.cedarsoft.com if you need additional information or
 * have any questions.
 */

package com.cedarsoft.codegen;

import com.cedarsoft.codegen.parser.Classpath;
import com.cedarsoft.execution.Executor;
import com.google.common.collect.ImmutableList;
import com.google.common.io.Files;
import com.sun.tools.xjc.api.util.APTClassLoader;
import com.sun.tools.xjc.api.util.ToolsJarNotFoundException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.fest.reflect.core.Reflection;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.List;

/**
 * Abstract base class for Generators.
 * Handles options and classloader issues
 */
public abstract class AbstractGenerator {
    @Nonnull
    public static final String GENERATE_METHOD_NAME = "generate";

    protected void run(@Nonnull Collection<? extends File> domainSourceFiles, @Nonnull File destination,
            @Nonnull File resourcesDestination, @Nonnull File testDestination,
            @Nonnull File testResourcesDestination, @Nullable Classpath classpath, @Nonnull PrintWriter logOut)
            throws ToolsJarNotFoundException, ClassNotFoundException, IOException, InterruptedException {
        GeneratorConfiguration configuration = new GeneratorConfiguration(domainSourceFiles, destination,
                resourcesDestination, testDestination, testResourcesDestination, classpath, logOut);

        File tmpDestination = createEmptyTmpDir();
        File tmpTestDestination = createEmptyTmpDir();

        File tmpResourcesDestination = createEmptyTmpDir();
        File tmpTestResourcesDestination = createEmptyTmpDir();

        GeneratorConfiguration tmpConfiguration = new GeneratorConfiguration(domainSourceFiles, tmpDestination,
                tmpResourcesDestination, tmpTestDestination, tmpTestResourcesDestination, classpath, logOut);

        //Now start the generator
        run(tmpConfiguration);

        transferFiles(tmpConfiguration, configuration);

        FileUtils.deleteDirectory(tmpDestination);
        FileUtils.deleteDirectory(tmpTestDestination);
    }

    public void run(@Nonnull GeneratorConfiguration configuration)
            throws ToolsJarNotFoundException, ClassNotFoundException {
        run(configuration, createRunner());
    }

    public void run(@Nonnull Class<?> runnerType, @Nonnull GeneratorConfiguration configuration)
            throws ToolsJarNotFoundException, ClassNotFoundException {
        run(configuration, createRunner(runnerType));
    }

    public void run(@Nonnull GeneratorConfiguration configuration, @Nonnull Object runner) {
        Reflection.method(GENERATE_METHOD_NAME).withParameterTypes(GeneratorConfiguration.class).in(runner)
                .invoke(configuration);
    }

    @Nonnull
    public Object createRunner() throws ToolsJarNotFoundException, ClassNotFoundException {
        Class<?> runnerType = getRunnerType();
        return createRunner(runnerType);
    }

    public Object createRunner(@Nonnull Class<?> runnerType) {
        return Reflection.constructor().in(runnerType).newInstance();
    }

    @Nonnull
    public Class<?> getRunnerType() throws ToolsJarNotFoundException, ClassNotFoundException {
        ClassLoader aptClassLoader = createAptClassLoader();
        Thread.currentThread().setContextClassLoader(aptClassLoader);

        return aptClassLoader.loadClass(getRunnerClassName());
    }

    /**
     * Transfers the files
     *
     * @param tmpConfiguration the temporary configuration (the source)
     * @param configuration    the configuration (the target)
     * @throws IOException
     * @throws InterruptedException
     */
    public void transferFiles(@Nonnull GeneratorConfiguration tmpConfiguration,
            @Nonnull GeneratorConfiguration configuration) throws IOException, InterruptedException {
        transferFiles(tmpConfiguration.getDestination(), configuration.getDestination(), configuration.getLogOut());
        transferFiles(tmpConfiguration.getResourcesDestination(), configuration.getResourcesDestination(),
                configuration.getLogOut());

        transferFiles(tmpConfiguration.getTestDestination(), configuration.getTestDestination(),
                configuration.getLogOut());
        transferFiles(tmpConfiguration.getTestResourcesDestination(), configuration.getTestResourcesDestination(),
                configuration.getLogOut());
    }

    @Nonnull
    public APTClassLoader createAptClassLoader() throws ToolsJarNotFoundException {
        return createAptClassLoader(getDefaultClassLoader());
    }

    @Nonnull
    public APTClassLoader createAptClassLoader(@Nonnull ClassLoader defaultClassLoader)
            throws ToolsJarNotFoundException {
        return new APTClassLoader(defaultClassLoader,
                getPackagePrefixes().toArray(new String[getPackagePrefixes().size()]));
    }

    @Nonnull
    public ClassLoader getDefaultClassLoader() {
        ClassLoader defaultClassLoader = getClass().getClassLoader();
        if (defaultClassLoader == null) {
            defaultClassLoader = ClassLoader.getSystemClassLoader();
        }
        return defaultClassLoader;
    }

    @Nonnull
    protected List<? extends String> getPackagePrefixes() {
        return ImmutableList.of("com.cedarsoft.codegen.", "com.sun.istack.tools.", "com.sun.tools.apt.",
                "com.sun.tools.javac.", "com.sun.tools.javadoc.", "com.sun.mirror.");
    }

    protected void transferFiles(@Nonnull File sourceDir, @Nonnull File destination, @Nonnull PrintWriter logOut)
            throws IOException, InterruptedException {
        Collection<? extends File> serializerFiles = FileUtils.listFiles(sourceDir, TrueFileFilter.INSTANCE,
                TrueFileFilter.INSTANCE);
        for (File serializerFile : serializerFiles) {
            String relativePath = calculateRelativePath(sourceDir, serializerFile);

            File targetFile = new File(destination, relativePath);
            if (targetFile.exists()) {
                Executor executor = new Executor(
                        new ProcessBuilder("meld", targetFile.getAbsolutePath(), serializerFile.getAbsolutePath()));
                executor.execute();
            } else {
                //Create the directory if necessary
                File targetDir = targetFile.getParentFile();
                if (!targetDir.isDirectory()) {
                    targetDir.mkdirs();
                }
                Files.move(serializerFile, targetFile);
            }
        }
    }

    @Nonnull
    protected static String calculateRelativePath(@Nonnull File dir, @Nonnull File serializerFile)
            throws IOException {
        return serializerFile.getCanonicalPath().substring(dir.getCanonicalPath().length() + 1);
    }

    @Nonnull
    public static File createEmptyTmpDir() {
        return Files.createTempDir();
    }

    @Nonnull
    protected abstract String getRunnerClassName();

    /**
     * The runner interface
     */
    public interface Runner {
        /**
         * Generates the code
         *
         * @param configuration the configuration
         * @throws Exception
         */
        void generate(@Nonnull GeneratorConfiguration configuration) throws Exception;
    }
}