Java tutorial
/* * Copyright 2006-2007 the original author or authors. * * 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 com.hmed.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager; import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo; 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. */ public class MultiConfigAwarePersistenceUnitManager extends DefaultPersistenceUnitManager { private final Logger logger = LoggerFactory.getLogger(MultiConfigAwarePersistenceUnitManager.class); private boolean strict = false; private String persistenceUnitName = "hmedDB"; 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 (logger.isDebugEnabled()) { logger.debug("Merging existing jar file urls " + mainPui.getJarFileUrls() + " to persistence unit [" + pui.getPersistenceUnitName() + "]"); } copyPersistenceUnit(mainPui, pui); if (logger.isDebugEnabled()) { logger.debug("Persistence unit[" + pui.getPersistenceUnitName() + "] has now " + "the following jar file urls " + pui.getJarFileUrls() + ""); } } else { if (logger.isDebugEnabled()) { logger.debug("Merging information from [" + pui.getPersistenceUnitName() + "] " + "to [" + mainPui.getPersistenceUnitName() + "]"); } mergePersistenceUnit(pui, mainPui); if (logger.isDebugEnabled()) { logger.debug("Persistence unit[" + mainPui.getPersistenceUnitName() + "] has now " + "the following jar file urls " + mainPui.getJarFileUrls() + ""); } } } else if (!pui.getPersistenceUnitName().equals(persistenceUnitName)) { logger.debug("Adding persistence unit [" + pui.getPersistenceUnitName() + "] as is (no merging)"); } } /** * 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; } /** * 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: * <ul> * <li><tt>pu-base</tt> will be merged</li> * <li><tt>pufoo</tt> will be merged</li> * <li><tt>base-pu</tt> will <b>not</b> be merged</li> * </ul> * 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; } /** * 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.getManagedClassNames().size() != 0) { for (String s : from.getManagedClassNames()) { if (logger.isDebugEnabled()) { logger.debug("Adding entity [" + s + "]"); } to.addManagedClassName(s); } if (logger.isDebugEnabled()) { logger.debug("Added [" + from.getManagedClassNames().size() + "] managed classes to " + "persistence unit[" + to.getPersistenceUnitName() + "]"); } } else { to.addJarFileUrl(from.getPersistenceUnitRootUrl()); if (logger.isDebugEnabled()) { logger.debug("Added [" + from.getPersistenceUnitRootUrl() + "] for entity scanning " + "to persistence unit[" + to.getPersistenceUnitName() + "]"); } } } /** * 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) { // Copy jar file urls for (URL url : from.getJarFileUrls()) { to.addJarFileUrl(url); } for (String s : from.getManagedClassNames()) { to.addManagedClassName(s); } } /** * 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())); } /** * 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) { if (strict) { return getPersistenceUnitInfo(pui.getPersistenceUnitName()); } else if (pui.getPersistenceUnitName().startsWith(persistenceUnitName)) { // We have a match, retrieve our persistence unit name then final MutablePersistenceUnitInfo 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!"); } return result; } // Nothing has been found return null; } }