blob: a64b9270f4dc5a88026c824bfc100919b60756f8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 1998, 2009 Oracle. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* The API for this class and its comments are derived from the JPA 2.0 specification
* which is developed under the Java Community Process (JSR 317) and is copyright
* Sun Microsystems, Inc.
*
* Contributors:
* dclarke - Java Persistence API 2.0 Public Draft
* Specification and licensing terms available from
* http://jcp.org/en/jsr/detail?id=317
* mkeith - Add ability to run in OSGi and other environments by making
* provider discovery a strategy. Also allow providers to be
* added and removed dynamically.
*
* EARLY ACCESS - PUBLIC DRAFT
* This is an implementation of an early-draft specification developed under the
* Java Community Process (JCP) and is made available for testing and evaluation
* purposes only. The code is not compatible with any specification of the JCP.
******************************************************************************/
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* Mike Keith - Add ability to run in OSGi and other environments by making
* provider discovery a strategy. Also allow providers to be added
* and removed dynamically.
*
* Mike Keith elects to include this software in this distribution under
* the CDDL license.
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package javax.persistence;
// J2SE imports
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.Map;
import java.util.HashSet;
import java.util.Enumeration;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// persistence imports
import javax.persistence.spi.PersistenceProvider;
/**
* Bootstrap class that is used to obtain an {@link EntityManagerFactory}.
*
* @since Java Persistence 1.0
*/
public class Persistence {
protected static Set<PersistenceProvider> providers = new HashSet<PersistenceProvider>();
// Used to resolve and return providers.
protected static ProviderResolver providerResolver = new DefaultProviderResolver();
/**
* Get the resolver being used to obtain the available providers.
*
* @return The resolver used to obtain all available providers
*/
public static ProviderResolver getProviderResolver() {
return providerResolver;
}
/**
* Set the resolver to an alternate provider resolution strategy
* (implemented externally). This can be used to override the default
* resolution strategy.
*
* @param resolver
* The resolver to use when obtaining all available providers
*/
public static void setProviderResolver(ProviderResolver resolver) {
providerResolver = resolver;
}
/**
* Create and return an EntityManagerFactory for the named persistence unit.
*
* @param persistenceUnitName
* The name of the persistence unit
* @return The factory that creates EntityManagers configured according to
* the specified persistence unit
*/
public static EntityManagerFactory createEntityManagerFactory(String persistenceUnitName) {
return createEntityManagerFactory(persistenceUnitName, null);
}
/**
* Create and return an EntityManagerFactory for the named persistence unit
* using the given properties.
*
* @param persistenceUnitName
* The name of the persistence unit
* @param properties
* Additional properties to use when creating the factory. The
* values of these properties override any values that may have
* been configured elsewhere.
* @return The factory that creates EntityManagers configured according to
* the specified persistence unit.
*/
public static EntityManagerFactory createEntityManagerFactory(String persistenceUnitName, Map properties) {
EntityManagerFactory emf = null;
if (providers.size() == 0) {
try {
providers.addAll(providerResolver.findAllProviders());
} catch (IOException exc) {
}
}
for (PersistenceProvider provider : providers) {
emf = provider.createEntityManagerFactory(persistenceUnitName, properties);
if (emf != null) {
break;
}
}
if (emf == null) {
throw new PersistenceException("No Persistence provider for EntityManager named " + persistenceUnitName);
}
return emf;
}
// ====================
// Internal API methods
// ====================
/**
* Dynamically add a provider to the set of available providers.
*/
public static void addProvider(PersistenceProvider provider) {
providers.add(provider);
}
/**
* Dynamically remove a named provider from the set of available providers.
*/
public static void removeProvider(String providerName) {
for (Iterator<PersistenceProvider> i = providers.iterator(); i.hasNext();) {
if (i.next().getClass().getName().equals(providerName)) {
i.remove();
}
}
}
/**
* Reinitialize to have no providers.
*/
public static void resetProviders() {
providers = new HashSet<PersistenceProvider>();
}
// ==============================================================
// Interface for overriding available provider discovery strategy
// ==============================================================
/**
* Interface used by the Persistence class to obtain all available
* persistence providers.
*/
public static interface ProviderResolver {
Collection<PersistenceProvider> findAllProviders() throws IOException;
}
// =============================
// Internal implementation class
// =============================
/**
* Default provider resolver class to use when none is explicitly set.
*
* Uses the META-INF/services approach as described in the Java Persistence
* specification. A getResources() call is made on the current context
* classloader to find the service provider files on the classpath. Any
* service files found are then read to obtain the classes that implement
* the persistence provider interface.
*/
public static class DefaultProviderResolver implements ProviderResolver {
public static final String PERSISTENCE_PROVIDER = "javax.persistence.spi.PersistenceProvider";
public static final String SERVICE_PROVIDER_FILE = "META-INF/services/" + PERSISTENCE_PROVIDER;
public Collection<PersistenceProvider> findAllProviders() throws IOException {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Enumeration<URL> resources = loader.getResources(SERVICE_PROVIDER_FILE);
Set<String> providerNames = new HashSet<String>();
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
InputStream is = url.openStream();
try {
providerNames.addAll(providerNamesFromReader(new BufferedReader(new InputStreamReader(is))));
} finally {
is.close();
}
}
Collection<PersistenceProvider> loadedProviders = new HashSet<PersistenceProvider>();
for (String s : providerNames) {
try {
loadedProviders.add((PersistenceProvider) loader.loadClass(s).newInstance());
} catch (ClassNotFoundException exc) {
} catch (InstantiationException exc) {
} catch (IllegalAccessException exc) {
}
}
return loadedProviders;
}
private static final Pattern nonCommentPattern = Pattern.compile("^([^#]+)");
private Set<String> providerNamesFromReader(BufferedReader reader) throws IOException {
Set<String> providerNames = new HashSet<String>();
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
Matcher m = nonCommentPattern.matcher(line);
if (m.find()) {
providerNames.add(m.group().trim());
}
}
return providerNames;
}
}
}