001/* 002 * Units of Measurement Implementation for Java SE 003 * Copyright (c) 2005-2017, 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 tec.uom.se.spi; 031 032import javax.measure.Quantity; 033import javax.measure.spi.QuantityFactory; 034import javax.measure.spi.ServiceProvider; 035import javax.measure.spi.SystemOfUnitsService; 036import javax.measure.spi.UnitFormatService; 037 038import tec.uom.se.quantity.DefaultQuantityFactory; 039 040import java.util.ArrayList; 041import java.util.Collections; 042import java.util.Comparator; 043import java.util.List; 044import java.util.Map; 045import java.util.ServiceLoader; 046import java.util.concurrent.ConcurrentHashMap; 047import java.util.logging.Level; 048import java.util.logging.Logger; 049 050/** 051 * This class extends the {@link javax.measure.spi.ServiceProvider} class and 052 * hereby uses the JDK {@link java.util.ServiceLoader} to load the required 053 * services. 054 * 055 * @author Werner Keil 056 * @version 0.9 057 */ 058public class DefaultServiceProvider extends ServiceProvider implements Comparable<ServiceProvider> { 059 /** 060 * List of services loaded, per class. 061 */ 062 @SuppressWarnings("rawtypes") 063 private final Map<Class, List<Object>> servicesLoaded = new ConcurrentHashMap<>(); 064 065 private static final Comparator<Object> SERVICE_COMPARATOR = DefaultServiceProvider::compareServices; 066 067 @SuppressWarnings("rawtypes") 068 private final Map<Class, QuantityFactory> QUANTITY_FACTORIES = new ConcurrentHashMap<>(); 069 070 /** 071 * Returns a priority value of 10. 072 * 073 * @return 10, overriding the default provider. 074 */ 075 @Override 076 public int getPriority() { 077 return 10; 078 } 079 080 /** 081 * Loads and registers services. 082 * 083 * @param serviceType 084 * The service type. 085 * @param <T> 086 * the concrete type. 087 * @return the items found, never {@code null}. 088 */ 089 protected <T> List<T> getServices(final Class<T> serviceType) { 090 @SuppressWarnings("unchecked") 091 List<T> found = (List<T>) servicesLoaded.get(serviceType); 092 if (found != null) { 093 return found; 094 } 095 096 return loadServices(serviceType); 097 } 098 099 protected <T> T getService(Class<T> serviceType) { 100 List<T> services = getServices(serviceType); 101 if (services.isEmpty()) { 102 return null; 103 } 104 return services.get(0); 105 } 106 107 static int compareServices(Object o1, Object o2) { 108 int prio1 = 0; 109 int prio2 = 0; 110// Priority prio1Annot = o1.getClass().getAnnotation(Priority.class); 111// if (prio1Annot != null) { 112// prio1 = prio1Annot.value(); 113// } 114// Priority prio2Annot = o2.getClass().getAnnotation(Priority.class); 115// if (prio2Annot != null) { 116// prio2 = prio2Annot.value(); 117// } 118 if (prio1 < prio2) { 119 return 1; 120 } 121 if (prio2 < prio1) { 122 return -1; 123 } 124 return o2.getClass().getSimpleName().compareTo(o1.getClass().getSimpleName()); 125 } 126 127 /** 128 * Loads and registers services. 129 * 130 * @param serviceType 131 * The service type. 132 * @param <T> 133 * the concrete type. 134 * @return the items found, never {@code null}. 135 */ 136 private <T> List<T> loadServices(final Class<T> serviceType) { 137 List<T> services = new ArrayList<>(); 138 try { 139 for (T t : ServiceLoader.load(serviceType)) { 140 services.add(t); 141 } 142 Collections.sort(services, SERVICE_COMPARATOR); 143 @SuppressWarnings("unchecked") 144 final List<T> previousServices = (List<T>) servicesLoaded.putIfAbsent(serviceType, (List<Object>) services); 145 return Collections.unmodifiableList(previousServices != null ? previousServices : services); 146 } catch (Exception e) { 147 Logger.getLogger(DefaultServiceProvider.class.getName()).log(Level.WARNING, 148 "Error loading services of type " + serviceType, e); 149 Collections.sort(services, SERVICE_COMPARATOR); 150 return services; 151 } 152 } 153 154 @Override 155 public int compareTo(ServiceProvider o) { 156 return Integer.compare(getPriority(), o.getPriority()); 157 } 158 159 @Override 160 public SystemOfUnitsService getSystemOfUnitsService() { 161 return getService(SystemOfUnitsService.class); 162 } 163 164 @Override 165 public UnitFormatService getUnitFormatService() { 166 return getService(UnitFormatService.class); 167 } 168 169 /** 170 * Return a factory for this quantity 171 * 172 * @param quantity 173 * the quantity type 174 * @return the {@link QuantityFactory} 175 * @throws NullPointerException 176 */ 177 @Override 178 @SuppressWarnings("unchecked") 179 public final <Q extends Quantity<Q>> QuantityFactory<Q> getQuantityFactory(Class<Q> quantity) { 180 if (quantity == null) 181 throw new NullPointerException(); 182 if (!QUANTITY_FACTORIES.containsKey(quantity)) { 183 synchronized (QUANTITY_FACTORIES) { 184 QUANTITY_FACTORIES.put(quantity, DefaultQuantityFactory.getInstance(quantity)); 185 } 186 } 187 return QUANTITY_FACTORIES.get(quantity); 188 } 189}