com.github.nill14.utils.init.impl.ServiceRegistry Maven / Gradle / Ivy
package com.github.nill14.utils.init.impl;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Qualifier;
import com.github.nill14.utils.init.api.BindingKey;
import com.github.nill14.utils.init.api.IBeanDescriptor;
import com.github.nill14.utils.init.api.IBeanInjector;
import com.github.nill14.utils.init.api.ILazyPojo;
import com.github.nill14.utils.init.api.IParameterType;
import com.github.nill14.utils.init.api.IPojoInitializer;
import com.github.nill14.utils.init.api.IPropertyResolver;
import com.github.nill14.utils.init.api.IServiceContext;
import com.github.nill14.utils.init.api.IServiceRegistry;
import com.github.nill14.utils.init.inject.PojoInjectionDescriptor;
import com.github.nill14.utils.init.meta.AnnotationScanner;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
/**
*
* The ServiceRegistry must not be serializable. Serializing the registry indicates a programming error.
*
*/
@Deprecated
public class ServiceRegistry implements IServiceRegistry {
private final ConcurrentHashMap> beans = new ConcurrentHashMap<>();
private final ConcurrentHashMap, Map>> services = new ConcurrentHashMap<>();
private final ConcurrentHashMap, Map>> qualifiers = new ConcurrentHashMap<>();
private final ServiceRegistryPropertyResolver resolver = new ServiceRegistryPropertyResolver();
public ServiceRegistry() {
}
private String generateGlobalName(Class> type) { //TODO make sure the generated name doesn't conflict
Named named = type.getAnnotation(Named.class);
if (named != null) {
return type.getTypeName() + "$" + named.value();
} else {
return type.getTypeName();
}
}
@Override
public void addService(Class serviceBean, IServiceContext context) {
addService(generateGlobalName(serviceBean), serviceBean, context);
}
private IPropertyResolver getResolver(IServiceContext context) {
Optional customResolver = context.getCustomResolver();
if (customResolver.isPresent()) {
ChainingPropertyResolver chainingPropertyResolver = new ChainingPropertyResolver();
chainingPropertyResolver.append(customResolver.get());
chainingPropertyResolver.append(resolver);
return chainingPropertyResolver;
} else {
return resolver;
}
}
@SuppressWarnings("unchecked")
private ILazyPojo newProxy(ILazyPojo> lazyPojo, Class serviceBean) {
// Object proxy = LazyJdkProxy.newProxy(lazyPojo);
// Object proxy = LazyJavassistProxy.newProxy(lazyPojo);
// return (ILazyPojo) LazyPojo.forSingleton(proxy, IPropertyResolver.empty());
return (ILazyPojo) lazyPojo;
}
@Override
public void addService(String name, Class serviceBean, IServiceContext context) {
IPropertyResolver resolver = getResolver(context);
ILazyPojo lazyPojo = LazyPojo.forBean(serviceBean, resolver);
ILazyPojo proxy = newProxy(lazyPojo, serviceBean);
IBeanDescriptor pd = new PojoInjectionDescriptor<>(serviceBean);
pd.getDeclaredTypes().forEach((type) -> addElement(type, name, proxy, getTypeQualifier(pd.getRawType())));
Object old = beans.put(name, proxy);
Preconditions.checkArgument(old == null, "Duplicate bean " + old);
}
@Override
public > void addServiceFactory(
Class iface, Class factoryBean, IServiceContext context) {
addServiceFactory(iface, generateGlobalName(iface), factoryBean, context);
}
@Override
public > void addServiceFactory(
Class iface, String name, Class factoryBean, IServiceContext context) {
IPropertyResolver resolver = getResolver(context);
ILazyPojo lazyPojo = LazyPojo.forProvider(factoryBean, resolver);
ILazyPojo proxy = newProxy(lazyPojo, factoryBean);
IBeanDescriptor pd = new PojoInjectionDescriptor<>(iface);
pd.getDeclaredTypes().forEach((type) -> addElement(type, name, proxy, getTypeQualifier(pd.getRawType())));
beans.put(name, proxy);
}
@Override
public S getService(Class iface) {
Optional optional = getOptionalService(iface);
Preconditions.checkArgument(optional.isPresent(), String.format("Missing %s", iface));
return iface.cast(optional.get());
}
@Override
public S getService(Class iface, String name) {
S service = iface.cast(beans.get(name));
Objects.requireNonNull(service);
return service;
}
@Override
public Optional getOptionalService(Class iface) {
Optional> first = getServiceMap(iface).values().stream().findFirst();
return first.map(ILazyPojo::getInstance);
}
@Override
public Optional getOptionalService(Class iface, String name) {
ILazyPojo> bean = beans.get(name);
if (bean != null && iface.isAssignableFrom(bean.getType().getRawType())) {
return Optional.of(iface.cast(bean.getInstance()));
}
return Optional.empty();
}
private void addElement(Class> registrable, String name, ILazyPojo> proxy, @Nullable Annotation qualifier) {
Map> s = services.computeIfAbsent(registrable, r -> new ConcurrentHashMap<>());
s.put(name, proxy);
if (qualifier != null) {
Map> q = this.qualifiers.computeIfAbsent(registrable, r -> new ConcurrentHashMap<>());
Object prev = q.put(qualifier, proxy);
Preconditions.checkArgument(prev == null,
String.format("Duplicate qualifier %s for type %s", qualifier, registrable));
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private Map> getServiceMap(Class registrable) {
Preconditions.checkNotNull(registrable);
Map map = services.getOrDefault(registrable, Collections.emptyMap());
if (map != null) {
return map;
} else {
return ImmutableMap.of();
}
}
@Override
public Collection getServices(Class registrable) {
Map> map = getServiceMap(registrable);
if (map != null) {
return ImmutableList.copyOf(map.values().stream().map(ILazyPojo::getInstance).iterator());
} else {
return ImmutableList.of();
}
}
@Override
public void addSingleton(T serviceBean) {
addSingleton(Objects.toString(serviceBean), serviceBean);
}
@SuppressWarnings("unchecked")
@Override
public void addSingleton(String name, T serviceBean) {
ILazyPojo pojo = LazyPojo.forSingleton(serviceBean, IPropertyResolver.empty());
IBeanDescriptor pd = new PojoInjectionDescriptor((Class) serviceBean.getClass());
pd.getDeclaredTypes().forEach((type) -> addElement(type, name, pojo, getTypeQualifier(pd.getRawType())));
beans.put(name, pojo);
}
public void addBinding(BindingKey> BindingKey, ILazyPojo> lazyPojo) {
String globalName = generateGlobalName(lazyPojo.getType().getRawType());
addElement(BindingKey.getRawType(), globalName, lazyPojo, BindingKey.getQualifier());
Object old = beans.put(globalName, lazyPojo);
Preconditions.checkArgument(old == null, "Duplicate bean " + old);
}
public Collection> getBeans() {
Builder> builder = ImmutableList.builder();
builder.addAll(services.keySet());
// builder.addAll(providers.values())
return builder.build();
}
public Collection getBeanNames() {
return beans.keySet();
}
public Map getBeansOfType(Class type) {
Map> map = getServiceMap(type);
return map.entrySet().stream().collect(
Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getInstance()));
}
public Object getBean(String name) {
ILazyPojo> pojo = beans.get(name);
if (pojo != null) {
return pojo.getInstance();
} else {
return null;
}
}
@Override
public IPropertyResolver toResolver() {
return resolver;
}
@Override
public IBeanInjector toBeanInjector() {
return new BeanInjector(toResolver());
}
@SuppressWarnings("serial")
private class ServiceRegistryPropertyResolver extends AbstractPropertyResolver {
public ServiceRegistryPropertyResolver() {
super();
}
@Override
protected Object findByQualifier(IParameterType type, Annotation qualifier) {
ILazyPojo> lazyPojo = qualifiers.getOrDefault(type.getRawType(), Collections.emptyMap()).get(qualifier);
if (lazyPojo != null) {
return lazyPojo.getInstance();
} else {
return null;
}
}
@Override
protected Object findByName(String name, IParameterType type) {
ILazyPojo> bean = beans.get(name);
if (bean != null && type.getToken().isAssignableFrom(bean.getType())) {
return bean.getInstance();
}
return null;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
protected Object findByType(IParameterType type) {
Class> clazz = type.getRawType();
Map> serviceMap = getServiceMap((Class) clazz);
Optional> first = serviceMap.values().stream().findFirst();
return first.map(x -> x.getInstance()).orElse(null);
}
@Override
protected Collection> findAllByType(IParameterType type) {
return getServices(type.getRawType());
}
};
private Annotation getTypeQualifier(Class> clazz) {
return AnnotationScanner.findQualifier(clazz).orElse(null);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy