
com.github.thorbenkuck.di.runtime.SynchronizedServiceLoader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of wire-di-runtime-environment Show documentation
Show all versions of wire-di-runtime-environment Show documentation
Easy and simple di using annotation processors
The newest version!
package com.github.thorbenkuck.di.runtime;
import com.github.thorbenkuck.di.domain.WireCapable;
import com.github.thorbenkuck.di.lang.DataAccess;
import com.github.thorbenkuck.di.runtime.exceptions.DiLoadingException;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.TimeUnit;
public abstract class SynchronizedServiceLoader {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@NotNull
protected final DataAccess dataAccess = new DataAccess();
protected volatile boolean loaded = false;
@NotNull
private final Map, List> mapping = new HashMap<>();
public void unload() {
dataAccess.write(() -> {
logger.info("Clearing cached mappings");
mapping.clear();
loaded = false;
});
}
public Timed load() {
// pre check to avoid unnecessary synchronization
if (loaded) {
return Timed.empty();
}
return dataAccess.write(() -> {
// Check again, to combat race conditions,
// where both threads pass the pre-checks
// and then, one after another enter this
// synchronized statement and then override
// the same instances.
// We want to ensure under any and all
// circumstance, that we only load once.
if (loaded) {
return Timed.empty();
}
logger.debug("Starting to load {}", serviceType());
Timed timed = Timed.of(() -> {
ServiceLoader.load(serviceType())
.forEach(this::register);
ServiceLoader.loadInstalled(serviceType())
.forEach(this::register);
loaded = true;
});
logger.info("Loading finished in {}ms", timed.get(TimeUnit.MILLISECONDS));
return timed;
});
}
@NotNull
protected abstract Class serviceType();
public final void register(@NotNull final T t) {
dataAccess.write(() -> {
logger.debug("Registering instance of type {} with wired types {}", t.getClass(), Arrays.toString(t.wiredTypes()));
for (final Class> wiredType : t.wiredTypes()) {
if (wiredType == null) {
throw new DiLoadingException("The WireCables " + t + " returned null as an identifiable type! This is not permitted.\n" +
"If you did not create your own instance, please submit your annotated class to github.");
}
logger.trace("Registering {} for {}", t, wiredType);
unsafeRegister(wiredType, t);
}
});
}
public final boolean isLoaded() {
return loaded;
}
protected void unsafeRegister(@NotNull final Class> type, @NotNull final T instance) {
final List providers = mapping.computeIfAbsent(type, (t) -> new ArrayList<>());
providers.add(instance);
}
@NotNull
protected Map, List> getAll() {
return mapping;
}
@NotNull
protected List unsafeGet(@NotNull final Class> type) {
return mapping.getOrDefault(type, Collections.emptyList());
}
@Override
@NotNull
public final String toString() {
return getClass().getSimpleName() + "{" +
"registrations=" + getAll() +
", loaded=" + loaded +
'}';
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy