/* * Copyright (c) 2009-2013 Clark & Parsia, LLC. <http://www.clarkparsia.com> * * 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.clarkparsia.empire.spi; import com.clarkparsia.empire.ds.DataSourceFactory; import com.clarkparsia.empire.ds.DataSource; import com.clarkparsia.empire.ds.DataSourceException; import com.clarkparsia.empire.ds.Alias; import com.clarkparsia.empire.config.EmpireConfiguration; import com.clarkparsia.empire.config.ConfigKeys; import com.clarkparsia.empire.impl.EntityManagerFactoryImpl; import com.google.common.collect.Maps; import com.google.inject.Inject; import com.google.inject.name.Named; import javax.persistence.EntityManagerFactory; import javax.persistence.spi.PersistenceProvider; import javax.persistence.spi.PersistenceUnitInfo; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * <p>Implementation of the JPA {@link PersistenceProvider} interface.</p> * * @author Michael Grove * @since 0.6 * @version 0.6.5 */ public final class EmpirePersistenceProvider implements PersistenceProvider { // TODO: should we keep factories created so that to factories created w/ the same name are == ? /** * Current DataSourceFactory "plugins" */ private final Set<DataSourceFactory> mFactories; /** * Application container configuration */ private final EmpireConfiguration mContainerConfig; /** * Create a new EmpirePersistenceProvider * @param theFactories the list of DataSourceFactory objects available * @param theContainerConfig the current empire configuration */ @Inject EmpirePersistenceProvider(Set<DataSourceFactory> theFactories, @Named("ec") EmpireConfiguration theContainerConfig) { mFactories = theFactories; mContainerConfig = theContainerConfig; Runtime.getRuntime().addShutdownHook(new Thread() { /** * @inheritDoc */ @Override public void run() { close(); } }); } /** * Close this provider */ public void close() { // no-op } /** * @inheritDoc */ @Override public EntityManagerFactory createEntityManagerFactory(final String theUnitName, final Map theMap) { DataSourceFactory aFactory = selectFactory(theUnitName, theMap); if (aFactory != null) { return new EntityManagerFactoryImpl(aFactory, createUnitConfig(theUnitName, theMap)); } else { return null; } } /** * @inheritDoc */ @Override public EntityManagerFactory createContainerEntityManagerFactory(final PersistenceUnitInfo thePersistenceUnitInfo, final Map theMap) { // TODO: there's a lot more options on PersistenceUnitInfo that we can use here. return createEntityManagerFactory(thePersistenceUnitInfo.getPersistenceUnitName(), theMap); } /** * Similar to {@link #createEntityManagerFactory} this creates a DataSource (instead of an EntityManagerFactory) * based on the current persistence context and additional provided context parameters. Essentially does the * same thing as createEntityManagerFactory without wrapping the DataSource in an EntityManager or providing * EntityManager specific configuration properties as can be done with the EntityManagerFactory. * @param theUnitName the persistence unit to create * @param theMap additional persistence context parameters * @return a new data source, or null if one cannot be created. * @throws com.clarkparsia.empire.ds.DataSourceException if there is an error while creating the data source */ public DataSource createDataSource(final String theUnitName, final Map theMap) throws DataSourceException { DataSourceFactory aFactory = selectFactory(theUnitName, theMap); if (aFactory != null) { return aFactory.create(createUnitConfig(theUnitName, theMap)); } else { return null; } } private DataSourceFactory selectFactory(final String theUnitName, final Map theMap) { Map<String, Object> aConfig = createUnitConfig(theUnitName, theMap); if (!aConfig.containsKey(ConfigKeys.FACTORY)) { return null; } final String aName = aConfig.get(ConfigKeys.FACTORY).toString().trim(); for (DataSourceFactory aFactory : mFactories) { String aAlias = aFactory.getClass().isAnnotationPresent(Alias.class) ? aFactory.getClass().getAnnotation(Alias.class).value() : ""; if (aAlias.equals(aName) || aFactory.getClass().getName().equals(aName)) { return aFactory; } } return null; } /** * Create the unit specific configuration properties by grabbing unit configuration from the Empire config and then * merging that with the request specific configuration parameters. * @param theUnitName the name of the persistence unit configuration to retrieve * @param theMap the additional configuration parameters to add to the defaults * @return the unit configuration */ private Map<String, Object> createUnitConfig(final String theUnitName, final Map theMap) { Map<String, Object> aConfig = Maps.newHashMap(); if (mContainerConfig.hasUnit(theUnitName)) { aConfig.putAll(mContainerConfig.getUnitConfig(theUnitName)); } aConfig.putAll(mContainerConfig.getGlobalConfig()); if (theMap != null) { aConfig.putAll(theMap); } aConfig.put(ConfigKeys.NAME, theUnitName); return aConfig; } }