net.ggtools.maven.ddlgenerator.MultiConfigAwarePersistenceUnitManager.java Source code

Java tutorial

Introduction

Here is the source code for net.ggtools.maven.ddlgenerator.MultiConfigAwarePersistenceUnitManager.java

Source

/*
 * This file is part of ddlGenerator. Copyright 2012 Christophe Labouisse
 *
 * ddlGenerator is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ddlGenerator 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ddlGenerator.  If not, see <http://www.gnu.org/licenses/>.
 */

package net.ggtools.maven.ddlgenerator;

import org.apache.maven.plugin.logging.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager;
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;

import javax.persistence.spi.PersistenceUnitInfo;
import java.net.URL;

/**
 * An extension to the {@link DefaultPersistenceUnitManager} that is able to
 * merge multiple <tt>persistence.xml</tt> associated to the same persistence
 * unit name.
 * <p/>
 * If a module persistence unit defines managed classes explicitly, only adds
 * the specified classes. If the module persistence unit does not define any
 * managed classes, module scanning is assumed: any entity classes defined in
 * the module holding the persistence unit will be associated to the main one.
 * <p/>
 * This class has been copied from http://bitlingo.com/tag/jpa/. I guess this is
 * the best version of this class among the ones I found on internet.
 */
public class MultiConfigAwarePersistenceUnitManager extends DefaultPersistenceUnitManager {

    @Autowired
    private Log log;

    /**
     * The strict.
     */
    private transient boolean strict = false;

    /**
     * The persistence unit name.
     */
    private transient String persistenceUnitName = "default";

    /**
     * Copies a persistence unit to another one. Takes care of copying both
     * managed classes and urls.
     *
     * @param from the persistence unit to copy
     * @param to   the target (copied) persistence unit
     */
    protected void copyPersistenceUnit(MutablePersistenceUnitInfo from, MutablePersistenceUnitInfo to) {
        for (String s : from.getMappingFileNames()) {
            to.addMappingFileName(s);
        }
        for (String s : from.getManagedClassNames()) {
            to.addManagedClassName(s);
        }
        // Copy jar file urls
        for (URL url : from.getJarFileUrls()) {
            to.addJarFileUrl(url);
        }
    }

    /**
     * Returns the main {@link MutablePersistenceUnitInfo} to use, based on the
     * given {@link MutablePersistenceUnitInfo} and the settings of the manager.
     * <p/>
     * In strict mode, returns the declared persistence unit with the specified
     * name. In non strict mode and if the specified <tt>pui</tt> starts with
     * the configured <tt>persistenceUnitName</tt>, returns the template
     * persistence unit info used for the merging.
     *
     * @param pui the persistence unit info to handle
     * @return the persistence unit info to use for the merging
     */
    private MutablePersistenceUnitInfo getMainPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
        MutablePersistenceUnitInfo result = null;
        if (strict) {
            return getPersistenceUnitInfo(pui.getPersistenceUnitName());
        }
        if (pui.getPersistenceUnitName().startsWith(persistenceUnitName)) {
            // We have a match, retrieve our persistence unit name then
            result = getPersistenceUnitInfo(persistenceUnitName);
            // Sanity check
            if (result == null) {
                throw new IllegalStateException("No persistence unit found with name [" + persistenceUnitName + "] "
                        + "so no merging is possible. It usually means that the bootstrap-persistence.xml has not been "
                        + "included in the list of persistence.xml location(s). Check your configuration as it "
                        + "should be the first in the list!");
            }
        }
        // Nothing has been found
        return result;
    }

    /**
     * Specifies whether the specified persistence unit is the template one we
     * use to merge.
     *
     * @param pui the persistence unit to test
     * @return <tt>true</tt> if the persistence unit is the target, template
     *         persistence unit
     */
    private boolean isApplicationPersistenceUnit(MutablePersistenceUnitInfo pui) {
        return (!strict && persistenceUnitName.equals(pui.getPersistenceUnitName()));
    }

    /**
     * Merges a persistence unit to another one. Takes care of handling both
     * managed classes and urls. If the persistence unit has managed classes,
     * only merge these and prevents scanning. If no managed classes are
     * available, add the url of the module for entity scanning.
     *
     * @param from the persistence unit to handle
     * @param to   the target (merged) persistence unit
     */
    protected void mergePersistenceUnit(MutablePersistenceUnitInfo from, MutablePersistenceUnitInfo to) {
        if (from.getMappingFileNames().size() != 0) {
            for (String s : from.getMappingFileNames()) {
                if (log.isDebugEnabled()) {
                    log.debug("Adding entity [" + s + "]");
                }
                to.addMappingFileName(s);
            }
            if (log.isDebugEnabled()) {
                log.debug("Added [" + from.getMappingFileNames().size() + "] mapping file to " + "persistence unit["
                        + to.getPersistenceUnitName() + "]");
            }
        } else if (from.getManagedClassNames().size() != 0) {
            for (String s : from.getManagedClassNames()) {
                if (log.isDebugEnabled()) {
                    log.debug("Adding entity [" + s + "]");
                }
                to.addManagedClassName(s);
            }
            if (log.isDebugEnabled()) {
                log.debug("Added [" + from.getManagedClassNames().size() + "] managed classes to "
                        + "persistence unit[" + to.getPersistenceUnitName() + "]");
            }
        } else {
            to.addJarFileUrl(from.getPersistenceUnitRootUrl());
            if (log.isDebugEnabled()) {
                log.debug("Added [" + from.getPersistenceUnitRootUrl() + "] for entity scanning "
                        + "to persistence unit[" + to.getPersistenceUnitName() + "]");
            }
        }
    }

    /**
     * {@inheritDoc}.
     */
    @Override
    public PersistenceUnitInfo obtainPersistenceUnitInfo(String puName) {
        PersistenceUnitInfo persistenceUnitInfo = super.obtainPersistenceUnitInfo(puName);
        persistenceUnitInfo.getJarFileUrls().remove(persistenceUnitInfo.getPersistenceUnitRootUrl());
        return persistenceUnitInfo;
    }

    /**
     * {@inheritDoc}.
     */
    @Override
    protected void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
        super.postProcessPersistenceUnitInfo(pui);

        // This our template persistence unit that we are post-processing
        // so let's just skip.
        if (isApplicationPersistenceUnit(pui)) {
            return;
        }

        final MutablePersistenceUnitInfo mainPui = getMainPersistenceUnitInfo(pui);

        if (strict) {
            pui.addJarFileUrl(pui.getPersistenceUnitRootUrl());
        }

        if (mainPui != null) {
            if (strict) {
                if (log.isDebugEnabled()) {
                    log.debug("Merging existing jar file urls " + mainPui.getJarFileUrls()
                            + " to persistence unit [" + pui.getPersistenceUnitName() + "]");
                }
                copyPersistenceUnit(mainPui, pui);
                if (log.isDebugEnabled()) {
                    log.debug("Persistence unit[" + pui.getPersistenceUnitName() + "] has now "
                            + "the following jar file urls " + pui.getJarFileUrls() + "");
                }
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("Merging information from [" + pui.getPersistenceUnitName() + "] " + "to ["
                            + mainPui.getPersistenceUnitName() + "]");
                }
                mergePersistenceUnit(pui, mainPui);
                if (log.isDebugEnabled()) {
                    log.debug("Persistence unit[" + mainPui.getPersistenceUnitName() + "] has now "
                            + "the following jar file urls " + mainPui.getJarFileUrls());
                }
            }
        } else if (!pui.getPersistenceUnitName().equals(persistenceUnitName)) {
            log.debug("Adding persistence unit [" + pui.getPersistenceUnitName() + "] as is (no merging)");
        }
    }

    /**
     * Sets the name of the persistence unit that should be used. If no such
     * persistence unit exists, an exception will be thrown, preventing the
     * factory to be created.
     * <p/>
     * When the <tt>strict</tt> mode is disabled, this name is used to find all
     * matching persistence units based on a prefix. Say for instance that the
     * <tt>persistenceUnitName</tt> to use is <tt>pu</tt>, the following
     * applies: pu-base will be merged pufoo will be merged base-pu will
     * <b>not</b> be merged Make sure to configure your entity manager factory
     * to use this name as the persistence unit
     *
     * @param persistenceUnitName the name of the persistence unit to use
     */
    public void setPersistenceUnitName(String persistenceUnitName) {
        this.persistenceUnitName = persistenceUnitName;
    }

    /**
     * Specifies if the manager should process the persistence units in strict
     * mode. When enabled, only the persistence unit that have the exact same
     * names as an existing one are merged. When disabled (the default), if the
     * name of the persistence unit matches the prefix, it is merged with the
     * persistence unit defined by the prefix.
     *
     * @param strict if merging occurs on an exact match or on the prefix only
     */
    public void setStrict(boolean strict) {
        this.strict = strict;
    }

}