1 /* 2 * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * * Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * * Neither the name of JSR-310 nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package org.threeten.bp.zone; 33 34 import java.util.ServiceConfigurationError; 35 import java.util.ServiceLoader; 36 import java.util.concurrent.atomic.AtomicBoolean; 37 import java.util.concurrent.atomic.AtomicReference; 38 39 /** 40 * Controls how the time-zone rules are initialized. 41 * <p> 42 * The default behavior is to use {@link ServiceLoader} to find instances of {@link ZoneRulesProvider}. 43 * Use the {@link #setInitializer(ZoneRulesInitializer)} method to replace this behavior. 44 * The initializer instance must perform the work of creating the {@code ZoneRulesProvider} within 45 * the {@link #initializeProviders()} method to ensure that the provider is not initialized too early. 46 * <p> 47 * <b>The initializer must be set before class loading of any other ThreeTen-Backport class to have any effect!</b> 48 * <p> 49 * This class has been added primarily for the benefit of Android. 50 */ 51 public abstract class ZoneRulesInitializer { 52 53 /** 54 * An instance that does nothing. 55 * Call {@link #setInitializer(ZoneRulesInitializer)} with this instance to 56 * block the service loader search. This will leave the system with no providers. 57 */ 58 public static final ZoneRulesInitializer DO_NOTHING = new DoNothingZoneRulesInitializer(); 59 60 private static final AtomicBoolean INITIALIZED = new AtomicBoolean(false); 61 private static final AtomicReference<ZoneRulesInitializer> INITIALIZER = new AtomicReference<ZoneRulesInitializer>(); 62 63 /** 64 * Sets the initializer to use. 65 * <p> 66 * This can only be invoked before the {@link ZoneRulesProvider} class is loaded. 67 * Invoking this method at a later point will throw an exception. 68 * 69 * @param initializer the initializer to use 70 * @throws IllegalStateException if initialization has already occurred or another initializer has been set 71 */ setInitializer(ZoneRulesInitializer initializer)72 public static void setInitializer(ZoneRulesInitializer initializer) { 73 if (INITIALIZED.get()) { 74 throw new IllegalStateException("Already initialized"); 75 } 76 if (!INITIALIZER.compareAndSet(null, initializer)) { 77 throw new IllegalStateException("Initializer was already set, possibly with a default during initialization"); 78 } 79 } 80 81 //----------------------------------------------------------------------- 82 // initialize the providers initialize()83 static void initialize() { 84 if (INITIALIZED.getAndSet(true)) { 85 throw new IllegalStateException("Already initialized"); 86 } 87 // Set the default initializer if none has been provided yet. 88 INITIALIZER.compareAndSet(null, new ServiceLoaderZoneRulesInitializer()); 89 INITIALIZER.get().initializeProviders(); 90 } 91 92 /** 93 * Initialize the providers. 94 * <p> 95 * The implementation should perform whatever work is necessary to initialize the providers. 96 * This will result in one or more calls to {@link ZoneRulesProvider#registerProvider(ZoneRulesProvider)}. 97 * <p> 98 * It is vital that the instance of {@link ZoneRulesProvider} is not created until this method is invoked. 99 * <p> 100 * It is guaranteed that this method will be invoked once and only once. 101 */ initializeProviders()102 protected abstract void initializeProviders(); 103 104 //----------------------------------------------------------------------- 105 /** 106 * Implementation that does nothing. 107 */ 108 static class DoNothingZoneRulesInitializer extends ZoneRulesInitializer { 109 110 @Override initializeProviders()111 protected void initializeProviders() { 112 } 113 } 114 115 /** 116 * Implementation that uses the service loader. 117 */ 118 static class ServiceLoaderZoneRulesInitializer extends ZoneRulesInitializer { 119 120 @Override initializeProviders()121 protected void initializeProviders() { 122 ServiceLoader<ZoneRulesProvider> loader = ServiceLoader.load(ZoneRulesProvider.class, ZoneRulesProvider.class.getClassLoader()); 123 for (ZoneRulesProvider provider : loader) { 124 try { 125 ZoneRulesProvider.registerProvider(provider); 126 } catch (ServiceConfigurationError ex) { 127 if (!(ex.getCause() instanceof SecurityException)) { 128 throw ex; 129 } 130 } 131 } 132 } 133 } 134 135 } 136