Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2014 Avanza Bank AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.avanza.astrix.modules;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.annotation.PreDestroy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class ModuleManager implements Modules {
private final Logger log = LoggerFactory.getLogger(ModuleManager.class);
private final ConcurrentMap, List> moduleByExportedType = new ConcurrentHashMap<>();
private final List moduleInstances = new CopyOnWriteArrayList<>();
private final ModuleInstancePostProcessors globalModuleBeanPostProcessors = new ModuleInstancePostProcessors();
void register(Module module) {
ModuleInstance moduleInstance = new ModuleInstance(module, globalModuleBeanPostProcessors);
moduleInstances.add(moduleInstance);
for (Class> exportedBean : moduleInstance.getExports()) {
getExportingModules(exportedBean).add(moduleInstance);
}
}
private List getExportingModules(Class> exportedType) {
List modules = moduleByExportedType.get(exportedType);
if (modules == null) {
modules = new LinkedList();
moduleByExportedType.put(exportedType, modules);
}
return modules;
}
@Override
public T getInstance(Class type) {
return new CircularModuleDependenciesAwareCreation().get(type);
}
@Override
public Collection getAll(Class type) {
return new CircularModuleDependenciesAwareCreation().getAll(type);
}
private List getModulesNames(List modules) {
List result = new ArrayList(modules.size());
for (ModuleInstance instance : modules) {
result.add(instance.getName());
}
return result;
}
public static class ModuleInstance {
private final ModuleInjector moduleInjector;
private final String moduleName;
public ModuleInstance(Module module, ModuleInstancePostProcessor moduleInstancePostProcessor) {
this.moduleName = getModuleName(module);
this.moduleInjector = new ModuleInjector(moduleName);
this.moduleInjector.registerBeanPostProcessor(moduleInstancePostProcessor);
module.prepare(new ModuleContext() {
@Override
public void bind(Class type, Class extends T> providerType) {
moduleInjector.bind(type, providerType);
}
@Override
public void bind(Class type, T provider) {
moduleInjector.bind(type, provider);
}
@Override
public void export(Class> type) {
if (!type.isInterface()) {
throw new IllegalArgumentException(String.format("Its only allowed to export interface types. module=%s exportedType=%s", moduleName, type));
}
moduleInjector.addExport(type);
}
@Override
public void importType(final Class type) {
if (!type.isInterface()) {
throw new IllegalArgumentException(String.format("Its only allowed to interface types. module=%s importedType=%s", moduleName, type));
}
moduleInjector.addImport(type);
}
});
}
private String getModuleName(Module module) {
return module.name();
}
public String getName() {
return this.moduleName;
}
public Set> getExports() {
return this.moduleInjector.getExports();
}
public T getInstance(final Class type, ImportedDependencies importedDependencies) {
return this.moduleInjector.getBean(type, importedDependencies);
}
public void destroy() {
this.moduleInjector.destroy();
}
}
@Override
@PreDestroy
public void destroy() {
for (ModuleInstance moduleInstance : this.moduleInstances) {
moduleInstance.destroy();
}
}
public static class CreationFrame {
private ModuleInstance module;
private Class> type;
public CreationFrame(ModuleInstance module, Class> type) {
this.module = module;
this.type = type;
}
@Override
public int hashCode() {
return Objects.hash(module, type);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CreationFrame other = (CreationFrame) obj;
return Objects.equals(module, other.module)
&& Objects.equals(type, other.type);
}
}
public class CircularModuleDependenciesAwareCreation {
private final Stack creationStack = new Stack<>();
public T get(final Class type) {
List exportingModules = moduleByExportedType.get(type);
if (exportingModules == null) {
throw new MissingProvider(type);
}
if (exportingModules.size() > 1) {
log.warn("Type exported by multiple modules. Using first registered provider. Ignoring export. type={} usedModule={} ignoredModules={}",
type.getName(),
exportingModules.get(0).getName(),
getModulesNames(exportingModules.subList(1, exportingModules.size())));
}
ModuleInstance exportingModule = exportingModules.get(0);
return getInstance(type, exportingModule);
}
public Collection getAll(Class type) {
List result = new ArrayList<>();
List exportingModules = moduleByExportedType.get(type);
if (exportingModules == null) {
return result;
}
for (ModuleInstance exportingModule : exportingModules) {
result.add(getInstance(type, exportingModule));
}
return result;
}
private T getInstance(final Class type, ModuleInstance exportingModule) {
CreationFrame creationFrame = new CreationFrame(exportingModule, type);
if (creationStack.contains(creationFrame)) {
CircularDependency circularDependency = new CircularDependency();
circularDependency.addToDependencyTrace(type, exportingModule.getName());
throw circularDependency;
}
creationStack.add(creationFrame);
T result = exportingModule.getInstance(type, new ImportedDependencies() {
@Override
public Collection getAll(Class type) {
return CircularModuleDependenciesAwareCreation.this.getAll(type);
}
@Override
public D get(Class type) {
return CircularModuleDependenciesAwareCreation.this.get(type);
}
});
creationStack.pop();
return result;
}
}
public void registerBeanPostProcessor(ModuleInstancePostProcessor beanPostProcessor) {
this.globalModuleBeanPostProcessors.add(beanPostProcessor);
}
}