001/*
002 * Units of Measurement API
003 * Copyright (c) 2014-2015, Jean-Marie Dautelle, Werner Keil, V2COM.
004 *
005 * All rights reserved.
006 *
007 * Redistribution and use in source and binary forms, with or without modification,
008 * are permitted provided that the following conditions are met:
009 *
010 * 1. Redistributions of source code must retain the above copyright notice,
011 *    this list of conditions and the following disclaimer.
012 *
013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
014 *    and the following disclaimer in the documentation and/or other materials provided with the distribution.
015 *
016 * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products
017 *    derived from this software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package javax.measure.spi;
031
032import static java.util.logging.Level.INFO;
033import static java.util.logging.Level.WARNING;
034
035import java.util.Collection;
036import java.util.ServiceLoader;
037import java.util.logging.Logger;
038
039/**
040 * This singleton provides access to the services available in the current runtime environment. The
041 * behavior can be adapted, by calling {@link #init(ServiceProvider)} before accessing any measurement
042 * services.
043 *
044 * @author <a href="mailto:[email protected]">Werner Keil</a>
045 * @version 0.5, October 4, 2015
046 */
047public final class Bootstrap {
048    /**
049     * The ServiceProvider used.
050     */
051    private static volatile ServiceProvider serviceProviderDelegate;
052    /**
053     * The shared lock instance user.
054     */
055    private static final Object LOCK = new Object();
056
057    /**
058     * Private singleton constructor.
059     */
060    private Bootstrap() {
061    }
062
063    /**
064     * Load the {@link ServiceProvider} to be used.
065     *
066     * @return {@link ServiceProvider} to be used for loading the services.
067     */
068    private static ServiceProvider loadDefaultServiceProvider() {
069        try {
070            for (ServiceProvider sp : ServiceLoader.load(ServiceProvider.class)) {
071                return sp;
072            }
073        } catch (Exception e) {
074            Logger.getLogger(Bootstrap.class.getName()).log(INFO, "No ServiceProvider loaded, using default.");
075        }
076        return new DefaultServiceProvider();
077    }
078
079    /**
080     * Replace the current {@link ServiceProvider} in use.
081     *
082     * @param serviceProvider the new {@link ServiceProvider}
083     * @return the removed , or null.
084     */
085    public static ServiceProvider init(ServiceProvider serviceProvider) {
086        if (serviceProvider == null) {
087                throw new NullPointerException();
088        }
089        synchronized (LOCK) {
090            if (Bootstrap.serviceProviderDelegate==null) {
091                Bootstrap.serviceProviderDelegate = serviceProvider;
092                Logger.getLogger(Bootstrap.class.getName()).log(INFO, 
093                                "Measurement Bootstrap: new ServiceProvider set: " + serviceProvider.getClass().getName());
094                return null;
095            } else {
096                ServiceProvider prevProvider = Bootstrap.serviceProviderDelegate;
097                Bootstrap.serviceProviderDelegate = serviceProvider;
098                Logger.getLogger(Bootstrap.class.getName()).log(WARNING, 
099                                "Measurement Bootstrap: ServiceProvider replaced: " + serviceProvider.getClass().getName());
100                return prevProvider;
101            }
102        }
103    }
104
105    /**
106     * Returns the current {@link ServiceProvider}. If necessary the {@link ServiceProvider} will be lazily loaded.
107     *
108     * @return the {@link ServiceProvider} used.
109     */
110    static ServiceProvider getServiceProvider() {
111        if (serviceProviderDelegate==null) {
112            synchronized (LOCK) {
113                if (serviceProviderDelegate==null) {
114                    serviceProviderDelegate = loadDefaultServiceProvider();
115                }
116            }
117        }
118        return serviceProviderDelegate;
119    }
120
121    /**
122     * Delegate method for {@link ServiceProvider#getServices(Class)}.
123     *
124     * @param serviceType the service type.
125     * @return the services found.
126     * @see ServiceProvider#getServices(Class)
127     */
128    public static <T> Collection<T> getServices(Class<T> serviceType) {
129        return getServiceProvider().getServices(serviceType);
130    }
131
132    /**
133     * Delegate method for {@link ServiceProvider#getService(Class)}.
134     *
135     * @param serviceType the service type.
136     * @return the service found, or {@code null}.
137     * @see ServiceProvider#getServices(Class)
138     */
139    public static <T> T getService(Class<T> serviceType) {
140        return getServiceProvider().getService(serviceType);
141    }
142}