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

net.yetamine.osgi.jdbc.internal.Activator Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2016 Yetamine
 *
 * 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 net.yetamine.osgi.jdbc.internal;

import java.security.AccessController;
import java.security.PrivilegedAction;
import java.sql.DriverManager;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.yetamine.osgi.jdbc.DriverProvider;
import net.yetamine.osgi.jdbc.DriverSequence;
import net.yetamine.osgi.jdbc.support.DriverManagerAdapter;
import net.yetamine.osgi.jdbc.support.DriverReference;

/**
 * Activates this bundle.
 */
public final class Activator implements BundleActivator {

    private static final Logger LOGGER = LoggerFactory.getLogger(Activator.class);

    /** Common driver registrar, used by the thunk. */
    private static final DriverRegistrar REGISTRAR = new DriverRegistrar();
    /** Common driver provider for the thunk, published as a service too. */
    private static volatile DriverProvider provider = DriverManagerAdapter.instance();
    /** Common supportive executor for running the weaving-related tasks. */
    private static volatile Executor executor = Runnable::run;

    /** Weaving hook service. */
    private DriverWeaving weavingService;
    /** Bundle extender implementation. */
    private BundleExtender bundleExtender;
    /** Driver tracking and providing service. */
    private DriverTracking providingService;
    /** Executor service to manage. */
    private ExecutorService executorService;

    /**
     * Creates a new instance.
     */
    public Activator() {
        // Default constructor
    }

    /**
     * Returns the current driver provider available for the thunk.
     *
     * @return the current driver provider
     */
    public static DriverProvider provider() {
        return provider;
    }

    /**
     * Returns the driver registrar available for the thunk.
     *
     * @return the driver registrar
     */
    public static DriverRegistrar registrar() {
        return REGISTRAR;
    }

    /**
     * Returns the current executor.
     *
     * @return the current executor
     */
    public static Executor executor() {
        return executor;
    }

    /**
     * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
     */
    public synchronized void start(BundleContext context) throws Exception {
        LOGGER.info("Activating JDBC support.");

        initializeDriverManager();

        bundleExtender = new BundleExtender(context, registrar());
        providingService = new DriverTracking(context);
        weavingService = new DriverWeaving(context);

        executorService = Executors.newSingleThreadExecutor(r -> {
            final Thread thread = new Thread(r, "net.yetamine.osgi.jdbc/WeavingSupport");
            thread.setDaemon(true);
            return thread;
        });

        executor = executorService::execute;   // Bind the execution method to avoid casting to ExecutorService

        weavingService.open();      // Firstly, start weaving, so the all loaded drivers could be woven
        bundleExtender.open();      // After weaving hook is ready, loading may start
        providingService.open();    // Finally, when some drivers are on the way, allow publishing them

        REGISTRAR.bind(context); // OK, wire it
        provider = providingService.provider();

        LOGGER.info("Activated JDBC support.");
    }

    /**
     * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
     */
    public synchronized void stop(BundleContext context) throws Exception {
        LOGGER.info("Deactivating JDBC support.");

        provider = DriverManagerAdapter.instance();
        REGISTRAR.release();

        providingService.close();   // Firstly, stop the provider to let its dependencies to shut down as soon as possible
        bundleExtender.close();     // Then ensure no more drivers could be loaded or published
        weavingService.close();     // Then it is possible to switch off the weaving

        executor = Runnable::run;
        executorService.shutdown();

        LOGGER.info("Deactivated JDBC support.");
    }

    /**
     * Forces {@link DriverManager} initialization, so that it does load initial
     * drivers in a clean context (hopefully). This is the best-effort way to
     * mitigate the shadows of the TCCL.
     */
    private static void initializeDriverManager() {
        final DriverSequence drivers;

        final ClassLoader current = Thread.currentThread().getContextClassLoader();
        try { // Trigger loading DriverManager and fetch the available drivers
            drivers = AccessController.doPrivileged((PrivilegedAction) () -> {
                Thread.currentThread().setContextClassLoader(null);
                return DriverManagerAdapter.instance().drivers();
            });
        } finally {
            Thread.currentThread().setContextClassLoader(current);
        }

        // Reuse the nice DriverReference::toString (and lazy formatting)
        drivers.forEach(driver -> LOGGER.info("Found bootstrap driver {}", new DriverReference(driver)));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy