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

io.polaris.core.service.StatefulServiceLoader Maven / Gradle / Ivy

There is a newer version: 3.2.1
Show newest version
package io.polaris.core.service;

import lombok.AccessLevel;
import lombok.Getter;

import javax.annotation.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Qt
 * @version Jan 13, 2022
 * @since 1.8
 */
public class StatefulServiceLoader implements Iterable {
	private final static Map, State> store = new ConcurrentHashMap<>();
	private final ServiceLoader serviceLoader;

	private StatefulServiceLoader(ServiceLoader serviceLoader) {
		this.serviceLoader = serviceLoader;
	}

	private StatefulServiceLoader(Class service, ClassLoader loader) {
		this(ServiceLoader.of(service, loader));
	}

	public static  StatefulServiceLoader load(Class service) {
		return load(service, Thread.currentThread().getContextClassLoader());
	}

	public static  StatefulServiceLoader load(Class service, ClassLoader classLoader) {
		StatefulServiceLoader loader = null;
		State ref = (State) store.get(service);
		if (ref == null) {
			synchronized (store) {
				ref = (State) store.get(service);
				if (ref == null) {
					loader = new StatefulServiceLoader<>(service, classLoader);
					ref = new State<>(classLoader, loader);
					store.put(service, ref);
				}
			}
		}
		if (loader == null) {
			loader = ref.getByClassLoader(classLoader);
			if (loader == null) {
				synchronized (ref) {
					loader = ref.getByClassLoader(classLoader);
					if (loader == null) {
						loader = new StatefulServiceLoader<>(service, classLoader);
						ref.update(classLoader, loader);
					}
				}
			}
		}
		return loader;
	}

	public static  void clear(Class service) {
		store.computeIfPresent(service, (k, v) -> {
			v.map.clear();
			return null;
		});
	}

	@Override
	public Iterator iterator() {
		return new Iterator() {
			final Iterator> iter = serviceLoader.iterator();

			@Override
			public boolean hasNext() {
				return iter.hasNext();
			}

			@Override
			public S next() {
				return iter.next().getSingleton();
			}
		};
	}


	public ServiceLoader serviceLoader() {
		return serviceLoader;
	}

	public Optional optionalService() {
		return Optional.ofNullable(serviceLoader.get()).map(Service::getSingleton);
	}

	@Nullable
	public S service() {
		return serviceLoader.getSingleton();
	}

	@Nullable
	public S service(String propertyName, String propertyValue) {
		return serviceLoader.getSingleton(propertyName, propertyValue);
	}

	public List serviceList() {
		List list = new ArrayList<>();
		for (Service service : serviceLoader) {
			list.add(service.getSingleton());
		}
		return list;
	}

	public Map serviceMap() {
		Map map = new HashMap<>();
		serviceLoader.getNamings().forEach((k, v) -> map.put(k, v.getSingleton()));
		return map;
	}

	/**
	 * @author Qt
	 * @version Jan 13, 2022
	 * @since 1.8
	 */
	static class State {
		private Map> map = new ConcurrentHashMap<>();
		@Getter(AccessLevel.PACKAGE)
		private ClassLoader lastClassLoader;
		@Getter(AccessLevel.PACKAGE)
		private StatefulServiceLoader lastServiceLoader;

		State(ClassLoader lastClassLoader, StatefulServiceLoader lastServiceLoader) {
			update(lastClassLoader, lastServiceLoader);
		}

		void update(ClassLoader lastClassLoader, StatefulServiceLoader lastServiceLoader) {
			this.lastClassLoader = lastClassLoader;
			this.lastServiceLoader = lastServiceLoader;
			this.map.put(lastClassLoader, lastServiceLoader);
		}

		StatefulServiceLoader getByClassLoader(ClassLoader loader) {
			if (lastClassLoader == loader) {
				return lastServiceLoader;
			}
			return map.get(loader);
		}

	}
}