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

io.datakernel.util.guice.GuiceUtils Maven / Gradle / Ivy

Go to download

An intelligent way of booting complex applications and services according to their dependencies

There is a newer version: 3.1.0
Show newest version
package io.datakernel.util.guice;

import com.google.inject.*;
import com.google.inject.spi.BindingScopingVisitor;
import com.google.inject.spi.DefaultBindingScopingVisitor;
import io.datakernel.annotation.Nullable;
import io.datakernel.util.SimpleType;
import io.datakernel.worker.WorkerPool;
import io.datakernel.worker.WorkerPoolScope;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

public final class GuiceUtils {
	private GuiceUtils() {
	}

	public static boolean isSingleton(Binding binding) {
		return binding.acceptScopingVisitor(new BindingScopingVisitor() {
			@Override
			public Boolean visitNoScoping() {
				return false;
			}

			@Override
			public Boolean visitScopeAnnotation(Class visitedAnnotation) {
				return visitedAnnotation.equals(Singleton.class);
			}

			@Override
			public Boolean visitScope(Scope visitedScope) {
				return visitedScope.equals(Scopes.SINGLETON);
			}

			@Override
			public Boolean visitEagerSingleton() {
				return true;
			}
		});
	}

	public static String prettyPrintAnnotation(Annotation annotation) {
		StringBuilder sb = new StringBuilder();
		Method[] methods = annotation.annotationType().getDeclaredMethods();
		boolean first = true;
		if (methods.length != 0) {
			for (Method m : methods) {
				try {
					Object value = m.invoke(annotation);
					if (value.equals(m.getDefaultValue()))
						continue;
					String valueStr = (value instanceof String ? "\"" + value + "\"" : value.toString());
					String methodName = m.getName();
					if ("value".equals(methodName) && first) {
						sb.append(valueStr);
						first = false;
					} else {
						sb.append(first ? "" : ",").append(methodName).append("=").append(valueStr);
						first = false;
					}
				} catch (ReflectiveOperationException ignored) {
				}
			}
		}
		String simpleName = annotation.annotationType().getSimpleName();
		return "@" + ("NamedImpl".equals(simpleName) ? "Named" : simpleName) + (first ? "" : "(" + sb + ")");
	}

	public static String prettyPrintSimpleKeyName(Key key) {
		Type type = key.getTypeLiteral().getType();
		return (key.getAnnotation() != null ? prettyPrintAnnotation(key.getAnnotation()) + " " : "") +
				SimpleType.ofType(type).getSimpleName();
	}

	public static String prettyPrintKeyName(Key key) {
		Type type = key.getTypeLiteral().getType();
		return (key.getAnnotation() != null ? prettyPrintAnnotation(key.getAnnotation()) + " " : "") +
				SimpleType.ofType(type).getName();
	}

	public static Integer extractWorkerId(Binding binding) {
		return binding.acceptScopingVisitor(new DefaultBindingScopingVisitor() {
			@Override
			@Nullable
			public Integer visitScope(Scope scope) {
				return scope instanceof WorkerPoolScope ? ((WorkerPoolScope) scope).getCurrentWorkerId() : null;
			}
		});
	}

	public static WorkerPool extractWorkerPool(Binding binding) {
		return binding.acceptScopingVisitor(new DefaultBindingScopingVisitor() {
			@Override
			@Nullable
			public WorkerPool visitScope(Scope scope) {
				return scope instanceof WorkerPoolScope ? ((WorkerPoolScope) scope).getCurrentWorkerPool() : null;
			}
		});
	}

	public interface ModuleWithRemapping extends com.google.inject.Module {
		 ModuleWithRemapping remap(Key key, Key to);

		 ModuleWithRemapping expose(Key key);
	}

	public static ModuleWithRemapping remapModule(com.google.inject.Module module) {
		return new ModuleWithRemapping() {
			Map, Key> remappedKeys = new LinkedHashMap<>();
			Set> exposedKeys = new LinkedHashSet<>();

			@Override
			public  ModuleWithRemapping remap(Key from, Key to) {
				remappedKeys.put(from, to);
				return this;
			}

			@Override
			public  ModuleWithRemapping expose(Key key) {
				exposedKeys.add(key);
				return this;
			}

			@Override
			public void configure(Binder binder) {
				final Map, Key> finalRemappedKeys = remappedKeys;
				Set> finalExposedKeys = this.exposedKeys;
				this.remappedKeys = null;
				this.exposedKeys = null;
				binder.install(new PrivateModule() {
					@Override
					protected void configure() {
						install(new PrivateModule() {
							@SuppressWarnings("unchecked")
							@Override
							protected void configure() {
								install(new PrivateModule() {
									@Override
									protected void configure() {
										install(module);
										for (Key key : finalExposedKeys) {
											expose(key);
										}
										for (Key key : finalRemappedKeys.keySet()) {
											expose(key);
										}
									}
								});
								for (Key key : finalExposedKeys) {
									expose(key);
								}
								for (Map.Entry, Key> entry : finalRemappedKeys.entrySet()) {
									bind((Key) entry.getValue()).to(entry.getKey());
								}
							}
						});
						for (Key key : finalExposedKeys) {
							expose(key);
						}
						for (Key key : finalRemappedKeys.values()) {
							expose(key);
						}
					}
				});
			}
		};
	}
}