org.mule.runtime.module.service.ReflectionServiceResolver Maven / Gradle / Ivy
/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.module.service;
import static java.util.stream.Collectors.toList;
import static org.mule.runtime.api.util.Preconditions.checkArgument;
import org.mule.runtime.api.service.Service;
import org.mule.runtime.api.service.ServiceDefinition;
import org.mule.runtime.api.service.ServiceProvider;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Resolves {@link Service} instances given a set of {@link ServiceProvider} instances.
*
* Resolution process consist if find, for each service provider, all the service dependencies it has. Then, service providers
* will be instantiated when the required set of dependencies is available.
*
* Resolution of services providers must be done always in the same order for the same set of providers to ensure a consistent
* startup of the container.
*
* In case of a missing dependency, the resolution will fail and the container should not start.
*/
public class ReflectionServiceResolver implements ServiceResolver {
private final ServiceProviderResolutionHelper serviceProviderResolutionHelper;
/**
* Creates a new instance.
*
* @param serviceProviderResolutionHelper utility used to process service providers. Non null.
*/
public ReflectionServiceResolver(ServiceProviderResolutionHelper serviceProviderResolutionHelper) {
checkArgument(serviceProviderResolutionHelper != null, "serviceProviderResolutionHelper cannot be null");
this.serviceProviderResolutionHelper = serviceProviderResolutionHelper;
}
@Override
public List resolveServices(List serviceProviders) throws ServiceResolutionError {
List dependencyAwareServiceProviders =
createDependencyAwareServiceProviders(serviceProviders);
Map, ServiceDefinition> registeredServices = new LinkedHashMap<>();
List unresolvedServiceProviders = new LinkedList<>(dependencyAwareServiceProviders);
List resolvedServiceProviders = new LinkedList<>();
boolean continueResolution = true;
while (continueResolution) {
int initialResolvedCount = resolvedServiceProviders.size();
List pendingUnresolvedServices = new LinkedList<>();
for (DependencyAwareServiceProvider dependencyAwareServiceProvider : unresolvedServiceProviders) {
if (isResolvedService(dependencyAwareServiceProvider, registeredServices.values())) {
serviceProviderResolutionHelper.injectInstance(dependencyAwareServiceProvider.serviceProvider,
registeredServices.values());
for (ServiceDefinition serviceDefinition : dependencyAwareServiceProvider.providedServices()) {
registeredServices.put(serviceDefinition.getServiceClass(), serviceDefinition);
}
resolvedServiceProviders.add(dependencyAwareServiceProvider);
} else {
pendingUnresolvedServices.add(dependencyAwareServiceProvider);
}
}
// Will try to resolve the services that are still unresolved
unresolvedServiceProviders = pendingUnresolvedServices;
continueResolution = resolvedServiceProviders.size() > initialResolvedCount;
}
if (!unresolvedServiceProviders.isEmpty()) {
final Set> dependencies = new HashSet<>();
for (DependencyAwareServiceProvider dependencyAwareServiceProvider : unresolvedServiceProviders) {
dependencies.addAll(dependencyAwareServiceProvider.getDependencies());
}
throw new ServiceResolutionError("Unable to resolve core service dependencies. Missing some of: " + dependencies);
}
return registeredServices.values().stream().map(s -> s.getService()).collect(toList());
}
private List createDependencyAwareServiceProviders(List serviceProviders) {
final List result = new ArrayList<>(serviceProviders.size());
for (ServiceProvider serviceProvider : serviceProviders) {
result.add(new DependencyAwareServiceProvider(serviceProvider,
serviceProviderResolutionHelper.findServiceDependencies(serviceProvider)));
}
result.sort((ServiceProvider p1, ServiceProvider p2) -> p1.getClass().getName().compareTo(p2.getClass().getName()));
return result;
}
private boolean isResolvedService(DependencyAwareServiceProvider dependencyAwareServiceProvider,
Collection resolvedServices) {
boolean resolvedCoreExtension = dependencyAwareServiceProvider.dependencies.isEmpty();
if (!resolvedCoreExtension && satisfiedDependencies(dependencyAwareServiceProvider.dependencies, resolvedServices)) {
resolvedCoreExtension = true;
}
return resolvedCoreExtension;
}
private boolean satisfiedDependencies(List> dependencies,
Collection resolvedServices) {
boolean resolvedDependency = true;
for (Class dependency : dependencies) {
resolvedDependency = false;
for (ServiceDefinition registeredService : resolvedServices) {
if (registeredService.getServiceClass().isAssignableFrom(dependency)) {
resolvedDependency = true;
}
}
if (!resolvedDependency) {
break;
}
}
return resolvedDependency;
}
private final class DependencyAwareServiceProvider implements ServiceProvider {
private final ServiceProvider serviceProvider;
private final List> dependencies;
DependencyAwareServiceProvider(ServiceProvider serviceProvider, List> dependencies) {
this.serviceProvider = serviceProvider;
this.dependencies = dependencies;
}
@Override
public List providedServices() {
return serviceProvider.providedServices();
}
List> getDependencies() {
return dependencies;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy