All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.osgijpa.extension.HybridPersistenceProviderResolver Maven / Gradle / Ivy

There is a newer version: 3.2-b03
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2010 Oracle and/or its affiliates. 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_1_1.html
 * or packager/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 packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * 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 org.glassfish.osgijpa.extension;

import org.glassfish.hk2.osgiresourcelocator.ServiceLoader;

import javax.persistence.spi.PersistenceProvider;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This is a custom implementation of {@link javax.persistence.spi.PersistenceProviderResolver} which has the ability
 * to discover providers that are part of OSGi bundles. As you know, a thread's context loader (TCL) is very widely
 * assumed to represent what an application can see. This is no different in JPA as well. However, there exists some
 * technologies like OSGi, which do not want to rely on Thread's context loader to denote visibility scope of an application.
 * In order to accommodate these diverse technologies, it first attempts to discover providers using TCL.
 * If some providers are visible to the TCL, it considers them as the only set of providers that are supposed to be
 * visible to the current thread and hence returns that list. If TCL can't find any providers, then it assumes that
 * it is invoked in a context which is not relying on TCL to limit visibility, hence  it goes onto discover all providers
 * installed in the current framework. To discover providers installed by OSGi bundles, it currently relies on
 * provider bundles to have META-INF/services/javax.persistence.PersistenceProvider file as every JPA compliant provider
 * bundles such a resource. In future, we can even enhance this class to discover PersistenceProvider service
 * registered by OSGi/JPA compliant bundles.
 * 

* As per the requirement of JPA spec, this implementation is thread-safe. * Please note, this class comes into picture even in Java EE mode usage of JPA via * {@link javax.persistence.spi.PersistenceProvider#getProviderUtil()}, which is the only way to call methods like * {@link javax.persistence.spi.ProviderUtil#isLoaded(Object)}. So, it is important for this class to be performant. * So, this class also supports caching mode which can be explicitly enabled at construction time. * Caching should only be enabled in environment where providers are not installed/uninstalled dynamically. * * @author [email protected] */ public class HybridPersistenceProviderResolver implements javax.persistence.spi.PersistenceProviderResolver { /* * Yes, I am fully aware that eclipselink produced javax.persistence bundle also has an activator * which has code to set a custom resolver, but that resolver only works for RFC#143 compliant OSGi JPA providers. * So, that does not work for us in GlassFish, as we are really a hybrid environment and our users primarily * use JPA in non-OSGi mode. SO, we need this resolver which caters to the need of both kinds of users. */ // Should we hold a WeakReference to provider instead of name of the provider? private final Map> cl2ProviderNames = Collections.synchronizedMap(new WeakHashMap>()); private final boolean cachingEnabled; private final Logger logger = Logger.getLogger(getClass().getPackage().getName()); public HybridPersistenceProviderResolver(boolean cachingEnabled) { logger.logp(Level.FINE, "HybridPersistenceProviderResolver", "HybridPersistenceProviderResolver", "cachingEnabled = {0}", new Object[]{cachingEnabled}); this.cachingEnabled = cachingEnabled; } public List getPersistenceProviders() { ClassLoader cl = Thread.currentThread().getContextClassLoader(); return getPersistenceProviders(cl); } private List getPersistenceProviders(ClassLoader cl) { List providers; if (isCachingEnabled()) { providers = readCache(cl); if (providers == null) { providers = discoverPersistenceProviders(cl); populateCache(cl, providers); } } else { providers = discoverPersistenceProviders(cl); } return providers; } private void populateCache(ClassLoader cl, List providers) { List providerNames = new ArrayList(providers.size()); providerNames.addAll(convert(providers)); cl2ProviderNames.put(cl, providerNames); } private List readCache(ClassLoader cl) { List providerNames = cl2ProviderNames.get(cl); return providerNames != null ? convert(providerNames, cl) : null; } /** * Converts a list of provider objects to a list of class names where each name corresponds to provider class name. * * @param providers list of providers * @return list of class names */ private List convert(Iterable providers) { List result = new ArrayList(); for (PersistenceProvider p : providers) { result.add(p.getClass().getName()); } return result; } /** * For each name passed in the list, it tries to load the class using the supplied loader, instantiate it * and adds it to the list of result object before returning it. If for some reason, the cached provider is * no longer available, then it just logs a warning and continues. Since we discover the providers using a single * class loader in {@link #discoverPersistenceProviders(ClassLoader)} (ClassLoader)} method, * we expect all of them to be loadable using the same loader as well. * * @param providerNames list of provider class names. * @param cl class loader to be used to load provider classes * @return list of provider objects. */ private List convert(Iterable providerNames, ClassLoader cl) { List result = new ArrayList(); for (String name : providerNames) { try { result.add((PersistenceProvider) cl.loadClass(name).newInstance()); } catch (Exception e) { logger.logp(Level.WARNING, "HybridPersistenceProviderResolver", "convert", "Exception trying to instantiate cached provider by name " + name, e); } } return result; } private List discoverPersistenceProviders(ClassLoader cl) { List result = new ArrayList(); if (cl != null) { Iterator services = java.util.ServiceLoader.load(PersistenceProvider.class, cl).iterator(); while (services.hasNext()) { try { PersistenceProvider p = services.next(); result.add(p); } catch (ServiceConfigurationError e) { // can happen if a cached provider has been uninstalled or something of that sort. logger.logp(Level.FINE, "HybridPersistenceProviderResolver", "getPersistenceProviders", "Exception while discovering providers for class loader " + cl, e); } } } if (result.isEmpty()) { // Ok, we are called in a context where TCL can't see any provider. e.g., // when an OSGi bundle's activator uses Persistence class. So, discover all providers installed // in the framework. result.addAll(discoverOSGiProviders()); } return result; } /** * @return persistence providers made available by OSGi bundles installed in the current framework. */ private List discoverOSGiProviders() { List result = new ArrayList(); for (PersistenceProvider p : ServiceLoader.lookupProviderInstances(PersistenceProvider.class)) { result.add(p); } return result; } public synchronized void clearCachedProviders() { if (isCachingEnabled()) { cl2ProviderNames.clear(); } } public boolean isCachingEnabled() { return cachingEnabled; } @Override public String toString() { return super.toString() + "[CachingEnabled = " + isCachingEnabled() + "]"; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy