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

tec.uom.se.spi.DefaultServiceProvider Maven / Gradle / Ivy

/*
 * Units of Measurement Implementation for Java SE
 * Copyright (c) 2005-2018, Jean-Marie Dautelle, Werner Keil, Otavio Santana.
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
 *    and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package tec.uom.se.spi;

import javax.measure.Quantity;
import javax.measure.spi.QuantityFactory;
import javax.measure.spi.ServiceProvider;
import javax.measure.spi.SystemOfUnitsService;
import javax.measure.spi.UnitFormatService;

import tec.uom.se.quantity.DefaultQuantityFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This class extends the {@link javax.measure.spi.ServiceProvider} class and
 * hereby uses the JDK {@link java.util.ServiceLoader} to load the required
 * services.
 *
 * @author Werner Keil
 * @version 0.9
 */
public class DefaultServiceProvider extends ServiceProvider implements Comparable {
	/**
	 * List of services loaded, per class.
	 */
	@SuppressWarnings("rawtypes")
	private final Map> servicesLoaded = new ConcurrentHashMap<>();

	private static final Comparator SERVICE_COMPARATOR = DefaultServiceProvider::compareServices;

	@SuppressWarnings("rawtypes")
	private final Map QUANTITY_FACTORIES = new ConcurrentHashMap<>();

	/**
	 * Returns a priority value of 10.
	 *
	 * @return 10, overriding the default provider.
	 */
	@Override
	public int getPriority() {
		return 10;
	}

	/**
	 * Loads and registers services.
	 *
	 * @param serviceType
	 *            The service type.
	 * @param 
	 *            the concrete type.
	 * @return the items found, never {@code null}.
	 */
	protected  List getServices(final Class serviceType) {
		@SuppressWarnings("unchecked")
		List found = (List) servicesLoaded.get(serviceType);
		if (found != null) {
			return found;
		}

		return loadServices(serviceType);
	}

	protected  T getService(Class serviceType) {
		List services = getServices(serviceType);
		if (services.isEmpty()) {
			return null;
		}
		return services.get(0);
	}

	static int compareServices(Object o1, Object o2) {
		int prio1 = 0;
		int prio2 = 0;
//		Priority prio1Annot = o1.getClass().getAnnotation(Priority.class);
//		if (prio1Annot != null) {
//			prio1 = prio1Annot.value();
//		}
//		Priority prio2Annot = o2.getClass().getAnnotation(Priority.class);
//		if (prio2Annot != null) {
//			prio2 = prio2Annot.value();
//		}
		if (prio1 < prio2) {
			return 1;
		}
		if (prio2 < prio1) {
			return -1;
		}
		return o2.getClass().getSimpleName().compareTo(o1.getClass().getSimpleName());
	}

	/**
	 * Loads and registers services.
	 *
	 * @param serviceType
	 *            The service type.
	 * @param 
	 *            the concrete type.
	 * @return the items found, never {@code null}.
	 */
	private  List loadServices(final Class serviceType) {
		List services = new ArrayList<>();
		try {
			for (T t : ServiceLoader.load(serviceType)) {
				services.add(t);
			}
			Collections.sort(services, SERVICE_COMPARATOR);
			@SuppressWarnings("unchecked")
			final List previousServices = (List) servicesLoaded.putIfAbsent(serviceType, (List) services);
			return Collections.unmodifiableList(previousServices != null ? previousServices : services);
		} catch (Exception e) {
			Logger.getLogger(DefaultServiceProvider.class.getName()).log(Level.WARNING,
					"Error loading services of type " + serviceType, e);
			Collections.sort(services, SERVICE_COMPARATOR);
			return services;
		}
	}

	@Override
	public int compareTo(ServiceProvider o) {
		return Integer.compare(getPriority(), o.getPriority());
	}

	@Override
	public SystemOfUnitsService getSystemOfUnitsService() {
		return getService(SystemOfUnitsService.class);
	}

	@Override
	public UnitFormatService getUnitFormatService() {
		return getService(UnitFormatService.class);
	}

	 /**
	   * Return a factory for this quantity
	   * 
	   * @param quantity
	   *          the quantity type
	   * @return the {@link QuantityFactory}
	   * @throws NullPointerException
	   */
	  @Override
	  @SuppressWarnings("unchecked")
	  public final > QuantityFactory getQuantityFactory(Class quantity) {
	    if (quantity == null)
	      throw new NullPointerException();
	    if (!QUANTITY_FACTORIES.containsKey(quantity)) {
	      synchronized (QUANTITY_FACTORIES) {
	        QUANTITY_FACTORIES.put(quantity, DefaultQuantityFactory.getInstance(quantity));
	      }
	    }
	    return QUANTITY_FACTORIES.get(quantity);
	  }
}