blob: 067a5b5562e2e5d45f42397dbb5749e479864091 [file] [log] [blame]
/*
* 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.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;
import java.util.HashMap;
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;
/**
* Bootstrap class to obtain {@link javax.persistence.EntityManagerFactory}
* references.
*
* Contains Geronimo implemented code as required by the JPA spec.
*
* @version $Rev$ $Date$
*/
public class Persistence {
// The following variable is only here for TCK backward compatibility
@Deprecated
protected static final Set<PersistenceProvider> providers = new HashSet<PersistenceProvider>();
// The following string is only here for TCK backward compatibility
@Deprecated
public static final 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();
public static EntityManagerFactory createEntityManagerFactory(
String persistenceUnitName) {
return createEntityManagerFactory(persistenceUnitName, Collections.EMPTY_MAP);
}
/**
* Geronimo implementation specific code
*/
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
List<PersistenceProvider> providers = getProviders();
/*
* Now, the default JPA2 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 that if we have more than one
* provider, then the other providers have a chance to return an EMF.
* Now, we will return any exceptions wrapped in a
* PersistenceException to match 1.0 behavior and provide more
* diagnostics to the end user.
*/
// capture any provider returned exceptions
Map<String, Throwable> exceptions = new HashMap<String, Throwable>();
// capture the provider names to use in the exception text if needed
StringBuffer foundProviders = null;
for (PersistenceProvider provider : providers) {
String providerName = provider.getClass().getName();
try {
factory = provider.createEntityManagerFactory(persistenceUnitName, props);
} catch (Exception e) {
// capture the exception details and give other providers a chance
exceptions.put(providerName, e);
}
if (factory != null) {
// we're done
return factory;
} else {
// update the list of providers we have tried
if (foundProviders == null) {
foundProviders = new StringBuffer(providerName);
} else {
foundProviders.append(", ");
foundProviders.append(providerName);
}
}
}
// make sure our providers list is initialized for the exceptions below
if (foundProviders == null) {
foundProviders = new StringBuffer("NONE");
}
/*
* 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.
*/
if (exceptions.isEmpty()) {
// throw an exception with the PU name and providers we tried
throw new PersistenceException("No persistence providers available for \"" + persistenceUnitName +
"\" after trying the following discovered implementations: " + foundProviders);
} else {
// we encountered one or more exceptions, so format and throw as a single exception
throw createPersistenceException(
"Explicit persistence provider error(s) occurred for \"" + persistenceUnitName +
"\" after trying the following discovered implementations: " + foundProviders,
exceptions);
}
}
/**
* Geronimo/OpenJPA private helper code for creating a PersistenceException
* @param msg String to use as the exception message
* @param failures Persistence provider exceptions to add to the exception message
* @return PersistenceException
*/
private static PersistenceException createPersistenceException(String msg, Map<String, Throwable> failures) {
String newline = System.getProperty("line.separator");
StringWriter strWriter = new StringWriter();
strWriter.append(msg);
if (failures.size() <= 1) {
// we caught an exception, so include it as the cause
Throwable t = null;
for (String providerName : failures.keySet()) {
t = failures.get(providerName);
strWriter.append(" from provider: ");
strWriter.append(providerName);
break;
}
return new PersistenceException(strWriter.toString(), t);
} else {
// we caught multiple exceptions, so format them into the message string and don't set a cause
strWriter.append(" with the following failures:");
strWriter.append(newline);
for (String providerName : failures.keySet()) {
strWriter.append(providerName);
strWriter.append(" returned: ");
failures.get(providerName).printStackTrace(new PrintWriter(strWriter));
}
strWriter.append(newline);
return new PersistenceException(strWriter.toString());
}
}
public static PersistenceUtil getPersistenceUtil() {
return new PersistenceUtilImpl();
}
public static void generateSchema(String persistenceUnitName, Map properties) {
final List<PersistenceProvider> providers = getProviders();
for (final PersistenceProvider provider : providers) {
if (provider.generateSchema( persistenceUnitName, properties)) {
return;
}
}
throw new PersistenceException("No provider for schema generation of unit '" + persistenceUnitName + "'");
}
private static List<PersistenceProvider> getProviders() {
// get the discovered set of providers
PersistenceProviderResolver resolver =
PersistenceProviderResolverHolder.getPersistenceProviderResolver();
// following will throw PersistenceExceptions for invalid services
return resolver.getPersistenceProviders();
}
/**
* 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) {
// Get the list of persistence providers from the resolver
List<PersistenceProvider> pps = getProviders();
// 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
List<PersistenceProvider> pps = getProviders();
// 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;
}
}
}