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

org.daisy.common.spi.ServiceLoader Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
package org.daisy.common.spi;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;

import com.google.common.collect.AbstractIterator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ServiceLoader implements Iterable {
	
	private static final Logger logger = LoggerFactory.getLogger(ServiceLoader.class);
	
	private static final Map,ServiceLoader> cache = new HashMap,ServiceLoader>();
	
	private static ClassLoader lastContextClassLoader = null;
	
	public static  ServiceLoader load(Class serviceType) {
		ClassLoader ccl = Thread.currentThread().getContextClassLoader();
		if (ccl != lastContextClassLoader) {
			cache.clear();
			Memoize.singletons.clear();
		}
		lastContextClassLoader = ccl;
		ServiceLoader loader;
		if (cache.containsKey(serviceType)) {
			loader = (ServiceLoader)cache.get(serviceType);
		} else {
			loader = new ServiceLoader(serviceType);
			cache.put(serviceType, loader);
		}
		return loader;
	}
	
	private Class serviceType;
	private Iterable serviceLoader;
	
	private ServiceLoader(Class serviceType) {
		this.serviceType = serviceType;
	}
	
	public Iterator iterator() {
		return new AbstractIterator() {
			Iterator serviceIterator;
			public S computeNext() {
				if (serviceIterator == null) {
					try {
						if (serviceLoader == null) {
							serviceLoader = memoize(java.util.ServiceLoader.load(serviceType));
						}
						serviceIterator = serviceLoader.iterator();
					} catch (Throwable e) {
						logger.error("Failed to instantiate services", e);
						return endOfData();
					}
				}
				while (serviceIterator.hasNext()) {
					try {
						return serviceIterator.next();
					} catch (Throwable e) {
						logger.error("Failed to instantiate service", e);
					}
				}
				return endOfData();
			}
		};
	}
	
	/*
	 * No two Iterables returned by this function contain multiple instances of the same class
	 */
	private static  Iterable memoize(final Iterable iterable) {
		return new Memoize() {
			protected Iterator _iterator() {
				return iterable.iterator();
			}
		};
	}
	
	private static abstract class Memoize implements Iterable {
		private static final Map,Object> singletons = new HashMap,Object>();
		private final ArrayList list = new ArrayList();
		protected abstract Iterator _iterator();
		private Iterator _iterator;
		public final Iterator iterator() {
			return new Iterator() {
				private int index = 0;
				public boolean hasNext() {
					synchronized(list) {
						if (index < list.size())
							return true;
						if (_iterator == null)
							_iterator = _iterator();
						return _iterator.hasNext();
					}
				}
				public S next() throws NoSuchElementException {
					synchronized(list) {
						if (index < list.size())
							return list.get(index++);
						if (_iterator == null)
							_iterator = _iterator();
						S next = _iterator.next();
						synchronized(singletons) {
							if (singletons.containsKey(next.getClass()))
								next = (S)singletons.get(next.getClass());
							else
								singletons.put(next.getClass(), next);
						}
						list.add(next);
						index++;
						return next;
					}
				}
				public void remove() {
					throw new UnsupportedOperationException();
				}
			};
		}
	}
}