org.codehaus.mojo.hibernate3.HibernateExporterMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.codehaus.mojo.hibernate3.HibernateExporterMojo.java

Source

package org.codehaus.mojo.hibernate3;

/*
 * Copyright 2005 Johann Reyes.
 *
 * 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.
 */

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.codehaus.mojo.hibernate3.configuration.ComponentConfiguration;
import org.codehaus.mojo.hibernate3.exporter.Component;
import org.codehaus.mojo.hibernate3.processor.ComponentPropertiesAware;
import org.codehaus.mojo.hibernate3.processor.CompositeProcessor;
import org.codehaus.mojo.hibernate3.processor.GeneratedClassProcessor;
import org.codehaus.mojo.hibernate3.processor.ProcessorUtil;
import org.codehaus.mojo.hibernate3.processor.implementations.NoOpProcessor;
import org.hibernate.exception.ExceptionUtils;
import org.hibernate.tool.hbm2x.Exporter;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.util.StringUtils;

import java.io.*;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;

/**
 * Base class for the different hibernate3 goals based on the Ant tasks of hibernate tools.
 *
 * @author <a href="mailto:jreyes@hiberforum.org">Johann Reyes</a>
 * @author <a href="mailto:tobrien@codehaus.org">Tim O'Brien</a>
 * @author Josh Long
 * @version $Id$
 * @requiresDependencyResolution test
 */
public abstract class HibernateExporterMojo extends AbstractMojo implements ExporterMojo {
    // ------------------------------ FIELDS ------------------------------

    /**
     * Parameter that holds components definitions specified by the user.
     *
     * @parameter
     * @noinspection MismatchedQueryAndUpdateOfCollection
     */
    private List components = new ArrayList();

    /**
     * Map holding the default component values for this goal.
     */
    private Map defaultComponents = new HashMap();

    /**
     * Parameter that holds component properties defined by the user. More information can be found at the
     * <a href="componentproperties.html">Component Properties Configuration</a> page.
     *
     * @parameter
     * @noinspection MismatchedQueryAndUpdateOfCollection
     */
    private Map componentProperties = new HashMap();

    /**
     * Spefic components configuration. More information can be found at the
     * <a href="components.html">Components Configuration</a> page.
     *
     * @component role="org.codehaus.mojo.hibernate3.configuration.ComponentConfiguration"
     * @noinspection MismatchedQueryAndUpdateOfCollection
     */
    private List componentConfigurations = new ArrayList();

    /**
     * <i>Maven Internal</i>: Project to interact with.
     *
     * @parameter expression="${project}"
     * @required
     * @readonly
     * @noinspection UnusedDeclaration
     */
    private MavenProject project;

    // --------------------- GETTER / SETTER METHODS ---------------------

    /**
     * @see ExporterMojo#getProject()
     */
    public MavenProject getProject() {
        return project;
    }

    // ------------------------ INTERFACE METHODS ------------------------

    // --------------------- Interface ExporterMojo ---------------------

    /**
     * @see ExporterMojo#getComponentProperty(String)
     */
    public String getComponentProperty(String key) {
        return getComponentProperty(key, null);
    }

    /**
     * @see ExporterMojo#getComponentProperty(String, boolean)
     */
    public boolean getComponentProperty(String key, boolean defaultValue) {
        String s = getComponentProperty(key);
        if (s == null) {
            return defaultValue;
        } else {
            //noinspection UnnecessaryUnboxing
            return Boolean.valueOf(s).booleanValue();
        }
    }

    // --------------------- Interface Mojo ---------------------

    /**
     * @see org.apache.maven.plugin.Mojo#execute()
     */
    public void execute() throws MojoExecutionException, MojoFailureException {
        Thread currentThread = Thread.currentThread();
        ClassLoader oldClassLoader = currentThread.getContextClassLoader();

        try {
            currentThread.setContextClassLoader(getClassLoader());
            if (getComponentProperty("skip", false)) {
                getLog().info("skipping hibernate3 execution");
            } else {
                doExecute();
            }
        } finally {
            currentThread.setContextClassLoader(oldClassLoader);
        }
    }

    // -------------------------- OTHER METHODS --------------------------

    /**
     * Adds a default goal.
     *
     * @param outputDirectory Default output directory
     * @param implementation  Default configuration implementation
     * @param jdk5            Is this goal being setup for jdk15?
     * @noinspection unchecked
     */
    protected void addDefaultComponent(String outputDirectory, String implementation, boolean jdk5) {
        Component component = new Component();
        component.setName(getName());
        component.setOutputDirectory(outputDirectory);
        getLog().info("output directory is " + outputDirectory);
        component.setImplementation(implementation);
        defaultComponents.put(jdk5 ? "jdk15" : "jdk14", component);
    }

    /**
     * Configures the Exporter.
     *
     * @param exporter Exporter to configure
     * @return Exporter
     * @throws MojoExecutionException if there is an error configuring the exporter
     * @noinspection unchecked
     */
    protected Exporter configureExporter(Exporter exporter) throws MojoExecutionException {

        String implementation = getComponentProperty("implementation", getComponent().getImplementation());

        ComponentConfiguration componentConfiguration = getComponentConfiguration(implementation);
        getLog().info("using " + componentConfiguration.getName() + " task.");

        Properties properties = new Properties();
        properties.putAll(componentProperties);

        exporter.setProperties(properties);
        exporter.setConfiguration(componentConfiguration.getConfiguration(this));
        exporter.setOutputDirectory(new File(getProject().getBasedir(), getComponent().getOutputDirectory()));

        File outputDir = getExporterOutputDir();
        if (getComponent().isCompileSourceRoot()) {
            // add output directory to compile roots
            getProject().addCompileSourceRoot(outputDir.getPath());
        }

        // now let's set the template path for custom templates if the directory exists
        // template path would need to be found inside the project directory
        String templatePath = getComponentProperty("templatepath", "/src/main/config/templates");
        File templatePathDir = new File(getProject().getBasedir(), templatePath);
        if (templatePathDir.exists() && templatePathDir.isDirectory()) {
            getLog().info("Exporter will use templatepath : " + templatePathDir.getPath());
            exporter.setTemplatePath(new String[] { templatePathDir.getPath() });
        }

        return exporter;
    }

    protected File getExporterOutputDir() {
        return new File(getProject().getBasedir(), getComponent().getOutputDirectory());
    }

    /**
     * Returns the ComponentConfiguration for this maven goal.
     *
     * @param name Configuration task name
     * @return ComponentConfiguration
     * @throws MojoExecutionException if there is an error finding the ConfigurationTask
     * @noinspection ForLoopReplaceableByForEach
     */
    protected ComponentConfiguration getComponentConfiguration(String name) throws MojoExecutionException {
        for (Iterator it = componentConfigurations.iterator(); it.hasNext();) {
            ComponentConfiguration componentConfiguration = (ComponentConfiguration) it.next();
            if (componentConfiguration.getName().equals(name)) {
                return componentConfiguration;
            }
        }
        throw new MojoExecutionException("Could not get ConfigurationTask.");
    }

    /**
     * @see ExporterMojo#getComponentProperty(String, String)
     */
    public String getComponentProperty(String key, String defaultValue) {
        String value = (String) componentProperties.get(key);
        if (value == null || "".equals(value.trim())) {
            return defaultValue;
        }
        return value;
    }

    /**
     * Gets the hibernate tool exporter based on the goal that is being called.
     *
     * @return Goal exporter
     */
    protected abstract Exporter createExporter();

    /**
     * Executes the plugin in an isolated classloader.
     *
     * @throws MojoExecutionException When there is an erro executing the plugin
     * @noinspection unchecked
     */
    protected void doExecute() throws MojoExecutionException {
        configureExporter(createExporter()).start();
    }

    protected void handleComposites() throws Throwable {
        String componentProperty = getComponentProperty("composite-processors", "");
        if (StringUtils.hasText(componentProperty)) {
            Class<? extends CompositeProcessor> clzz = (Class<? extends CompositeProcessor>) Class
                    .forName(componentProperty);
            ;
            CompositeProcessor cp = clzz.newInstance();
            handleProcessor(cp.getProcessors());
        }
    }

    protected void handleProcessor() throws Throwable {
        String clzzNameForProcessor = getComponentProperty("processors", NoOpProcessor.class.getName());
        if (StringUtils.hasText(clzzNameForProcessor)) {
            List<GeneratedClassProcessor> processors = ProcessorUtil.buildProcessorsFromProperty(",",
                    clzzNameForProcessor);
            handleProcessor(processors);
        }
    }

    @SuppressWarnings("unchecked")
    protected void handleProcessor(List<GeneratedClassProcessor> processors) throws Throwable {
        try {
            for (GeneratedClassProcessor processor : processors) {

                // make sure the processors have their dependencies ... ugh.
                if (processor instanceof ComponentPropertiesAware) {
                    ((ComponentPropertiesAware) processor).setComponentProperties(this.componentProperties);
                }

                getLog().info("Using " + processor.getClass().getName());

                Iterator<File> javaFiles = FileUtils.iterateFiles(getExporterOutputDir(), new String[] { "java" },
                        true);

                while (javaFiles.hasNext()) {
                    File f = javaFiles.next();
                    Reader reader = null;
                    Writer writer = null;
                    try {
                        reader = new BufferedReader(new FileReader(f));

                        String contents = IOUtils.toString(reader);

                        writer = new FileWriter(f);

                        String result = processor.processClass(f, contents);
                        getLog().info("processed " + f.getAbsolutePath() + ".");

                        IOUtils.write(result, writer);
                    } finally {
                        if (null != reader) {
                            IOUtils.closeQuietly(reader);
                        }
                        if (null != writer) {
                            IOUtils.closeQuietly(writer);
                        }
                    }
                }
            }

        } catch (Exception e) {
            getLog().error("couldn't load and delegate to the processor classes configured. "
                    + ExceptionUtils.getFullStackTrace(e));

        }
    }

    /**
     * Builds a proxy that will respect any configured processor instance if configured. This should only be called on subclasses that end up generated java classes.
     *
     * @param delegate the original Exporter
     * @return an Exporter proxy that will correctly give the processor objects a chance to run after the delegate exporters' start() method's been called.
     */
    protected Exporter buildProcessorAwareExporter(final Exporter delegate) {

        MethodInterceptor interceptor = new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                Method method = invocation.getMethod();
                Object[] objects = invocation.getArguments();

                Object result;
                try {
                    result = method.invoke(delegate, objects);
                    if (method.getName().contains("start")) {
                        handleComposites();
                        handleProcessor();
                    }
                    return result;
                } catch (Throwable throwable) {
                    getLog().error(throwable);
                }
                return null;

            }
        };

        ProxyFactoryBean bean = new ProxyFactoryBean();
        bean.addAdvice(interceptor);
        bean.setProxyTargetClass(true);
        bean.setBeanClassLoader(delegate.getClass().getClassLoader());
        bean.setAutodetectInterfaces(true);
        bean.setTarget(delegate);
        return (Exporter) bean.getObject();
    }

    /**
     * Returns the an isolated classloader.
     *
     * @return ClassLoader
     * @noinspection unchecked
     */
    private ClassLoader getClassLoader() {
        try {
            List classpathElements = project.getCompileClasspathElements();
            classpathElements.add(project.getBuild().getOutputDirectory());
            classpathElements.add(project.getBuild().getTestOutputDirectory());
            URL urls[] = new URL[classpathElements.size()];
            for (int i = 0; i < classpathElements.size(); ++i) {
                urls[i] = new File((String) classpathElements.get(i)).toURL();
            }
            return new URLClassLoader(urls, this.getClass().getClassLoader());
        } catch (Exception e) {
            getLog().debug("Couldn't get the classloader.");
            return this.getClass().getClassLoader();
        }
    }

    /**
     * Returns the parsed goal to the exporter.
     *
     * @return Component
     * @noinspection ForLoopReplaceableByForEach
     */
    protected Component getComponent() {
        Component defaultGoal = (Component) defaultComponents.get(HibernateUtils.getJavaVersion());
        if (!components.isEmpty()) {
            // add an alias to the report goal
            String name = getName();
            if ("report".equals(name)) {
                name = "hbm2doc";
            }

            // now iterate throught the goals
            for (Iterator it = components.iterator(); it.hasNext();) {
                Component component = (Component) it.next();
                if (name.equals(component.getName())) {
                    if (component.getImplementation() == null) {
                        component.setImplementation(defaultGoal.getImplementation());
                    }
                    if (component.getOutputDirectory() == null) {
                        component.setOutputDirectory(defaultGoal.getOutputDirectory());
                    }
                    return component;
                }
            }
        }
        return defaultGoal;
    }
}