/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ // // This source code implements specifications defined by the Java // Community Process. In order to remain compliant with the specification // DO NOT add / change / or delete method signatures! // package javax.persistence; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.persistence.spi.LoadState; import javax.persistence.spi.PersistenceProvider; import javax.persistence.spi.PersistenceProviderResolver; import javax.persistence.spi.PersistenceProviderResolverHolder; import javax.persistence.spi.ProviderUtil; /** * @version $Rev$ $Date$ */ /** * Bootstrap class that is used to obtain {@link javax.persistence.EntityManagerFactory} * references. * * Contains Geronimo implemented code as required by the JPA spec. */ public class Persistence { protected static final Set providers = new HashSet(); // Changed to the hard coded PERSISTENCE_PROVIDER value to pass signature tests. // public static final java.lang.String PERSISTENCE_PROVIDER = PersistenceProvider.class.getName(); public static final java.lang.String PERSISTENCE_PROVIDER = "javax.persistence.spi.PeristenceProvider"; static final String PERSISTENCE_PROVIDER_PROPERTY = "javax.persistence.provider"; static final String PERSISTENCE_PROVIDER_SERVICE = "META-INF/services/" + PersistenceProvider.class.getName(); /** * Create and return an EntityManagerFactory for the named persistence unit. * * @param persistenceUnitName Name of the persistence unit * @return The factory for the specified persistence unit or null if none * are applicable. */ public static EntityManagerFactory createEntityManagerFactory( String persistenceUnitName) { return createEntityManagerFactory(persistenceUnitName, Collections.EMPTY_MAP); } /** * Create and return an EntityManagerFactory for the named persistence unit * using the given properties. * * @param persistenceUnitName Name of the persistence unit * @param properties Additional properties to use when creating the * persistence unit factory. These properties override any * values that have been configured elsewhere. * @return The factory for the specified persistence unit or null if none * are applicable. */ public static EntityManagerFactory createEntityManagerFactory( String persistenceUnitName, Map properties) { EntityManagerFactory factory = null; Map props = properties; if (props == null) { props = Collections.EMPTY_MAP; } // get the discovered set of providers PersistenceProviderResolver resolver = PersistenceProviderResolverHolder.getPersistenceProviderResolver(); // following will throw PersistenceExceptions for invalid services List providers = resolver.getPersistenceProviders(); /* * Geronimo/OpenJPA 1.0 unique behavior - Start by loading a provider * explicitly specified in the properties and return any exceptions. * The spec doesn't forbid providers that aren't a service - it only * states that they "should" be implemented as services in Sect. 9.2. * * For 2.0 - We only perform the above behavior if the specified * provider is not in the discovered list. * * Note: This special non-spec defined case will rethrow any encountered * Exceptions as a PersistenceException. */ Object providerName = props.get(PERSISTENCE_PROVIDER_PROPERTY); if ((providerName != null) && (providerName instanceof String)) { boolean isLoaded = false; // search the discovered providers for this explicit provider for (PersistenceProvider provider : providers) { if (provider.getClass().getName().compareTo(providerName.toString()) == 0) { isLoaded = true; break; } } /* * Only try to explicitly create this provider if we didn't * find it as a service, while rethrowing any exceptions to * match the old 1.0 behavior */ if (!isLoaded) { factory = createFactory( providerName.toString(), persistenceUnitName, props); if (factory != null) { return factory; } } } /* * Now, the default behavior of loading a provider from our resolver * Note: Change in behavior from 1.0, which always returned exceptions: * Spec states that a provider "must" return null if it * cannot fulfill an EMF request, so ignore any exceptions * that are thrown if we have more than one provider, * so the other providers have a chance to return an EMF. * Otherwise, return any exceptions and rethrow/wrapper as a * PersistenceException if needed to match 1.0 behavior. */ if (providers.size() == 1) { // allow any exceptions to pass thru to caller return providers.get(0).createEntityManagerFactory( persistenceUnitName, props); } else { for (PersistenceProvider provider : providers) { try { factory = provider.createEntityManagerFactory( persistenceUnitName, props); } catch (Exception e) { // ignore and give other providers a chance } if (factory != null) { return factory; } } } /* * Spec doesn't mention any exceptions thrown by this method if no emf * returned, but old 1.0 behavior always generated an EMF or exception. */ throw new PersistenceException("No Persistence providers found for PU=" + persistenceUnitName); } /* * Geronimo/OpenJPA private helper code for PERSISTENCE_PROVIDER_PROPERTY * @return EntityManagerFactory or null * @throws PersistenceException */ private static EntityManagerFactory createFactory(String providerName, String persistenceUnitName, Map properties) throws PersistenceException { Class providerClass; // get our class loader ClassLoader cl = PrivClassLoader.get(null); if (cl == null) cl = PrivClassLoader.get(Persistence.class); try { providerClass = Class.forName(providerName, true, cl); } catch (Exception e) { throw new PersistenceException("Invalid or inaccessible explicit provider class: " + providerName, e); } try { PersistenceProvider provider = (PersistenceProvider) providerClass.newInstance(); return provider.createEntityManagerFactory(persistenceUnitName, properties); } catch (Exception e) { throw new PersistenceException("Explicit error returned from provider: " + providerName, e); } } /* * @return PersistenceUtil instance * @since 2.0 */ public static PersistenceUtil getPersistenceUtil() { return new PersistenceUtilImpl(); } /* * Geronimo implementation specific code */ private static class PersistenceUtilImpl implements PersistenceUtil { /* * Determines the load state of the attribute of an entity * @see javax.persistence.PersistenceUtil#isLoaded(java.lang.Object, java.lang.String) */ public boolean isLoaded(Object entity, String attributeName) { boolean isLoaded = true; // Get the list of persistence providers from the resolver PersistenceProviderResolver ppr = PersistenceProviderResolverHolder.getPersistenceProviderResolver(); List pps = ppr.getPersistenceProviders(); // Iterate through the list using ProviderUtil.isLoadedWithoutReference() for (PersistenceProvider pp : pps) { try { ProviderUtil pu = pp.getProviderUtil(); LoadState ls = pu.isLoadedWithoutReference(entity, attributeName); if (ls == LoadState.LOADED) return true; if (ls == LoadState.NOT_LOADED) return false; } catch (Throwable t) { // JPA 1.0 providers will not implement the getProviderUtil // method. Eat the exception and try the next provider. } } // Iterate through the list a second time using ProviderUtil.isLoadedWithReference() for (PersistenceProvider pp : pps) { try { ProviderUtil pu = pp.getProviderUtil(); LoadState ls = pu.isLoadedWithReference(entity, attributeName); if (ls == LoadState.LOADED) return true; if (ls == LoadState.NOT_LOADED) return false; } catch (Throwable t) { // JPA 1.0 providers will not implement the getProviderUtil // method. Eat the exception and try the next provider. } } // All providers returned a load state of unknown. Return true. return true; } public boolean isLoaded(Object entity) { // Get the list of persistence providers from the resolver PersistenceProviderResolver ppr = PersistenceProviderResolverHolder.getPersistenceProviderResolver(); List pps = ppr.getPersistenceProviders(); // Iterate through the list of providers, using ProviderUtil to // determine the load state for (PersistenceProvider pp : pps) { try { ProviderUtil pu = pp.getProviderUtil(); LoadState ls = pu.isLoaded(entity); if (ls == LoadState.LOADED) return true; if (ls == LoadState.NOT_LOADED) return false; // Otherwise, load state is unknown. Query the next provider. } catch (Throwable t) { // JPA 1.0 providers will not implement the getProviderUtil // method. Eat the exception and try the next provider. } } // All providers returned a load state of unknown. Return true. return true; } } private static class PrivClassLoader implements PrivilegedAction { private final Class c; public static ClassLoader get(Class c) { final PrivClassLoader action = new PrivClassLoader(c); if (System.getSecurityManager() != null) return AccessController.doPrivileged(action); else return action.run(); } private PrivClassLoader(Class c) { this.c = c; } public ClassLoader run() { if (c != null) return c.getClassLoader(); else return Thread.currentThread().getContextClassLoader(); } } }