/* * 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.launcher.coreextension; import org.mule.runtime.container.api.CoreExtensionsAware; import org.mule.runtime.container.api.MuleCoreExtension; import org.mule.runtime.api.exception.MuleRuntimeException; import org.mule.runtime.core.api.registry.IllegalDependencyInjectionException; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; /** * Resolves dependencies using reflection to inject the required {@link MuleCoreExtension} in the dependant instance. */ public class ReflectionMuleCoreExtensionDependencyResolver implements MuleCoreExtensionDependencyResolver { private final MuleCoreExtensionDependencyDiscoverer dependencyDiscoverer; public ReflectionMuleCoreExtensionDependencyResolver() { this(new ReflectionMuleCoreExtensionDependencyDiscoverer()); } public ReflectionMuleCoreExtensionDependencyResolver(MuleCoreExtensionDependencyDiscoverer dependencyDiscoverer) { this.dependencyDiscoverer = dependencyDiscoverer; } @Override public List<MuleCoreExtension> resolveDependencies(Collection<MuleCoreExtension> coreExtensions) { List<MuleCoreExtension> sortedCoreExtensions = new LinkedList<>(coreExtensions); sortCoreExtensionsByName(sortedCoreExtensions); List<MuleCoreExtension> coreExtensionAwareExtensions = findCoreExtensionAwareExtensions(sortedCoreExtensions); sortedCoreExtensions.removeAll(coreExtensionAwareExtensions); List<MuleCoreExtension> resolvedExtensions = resolveCoreExtensionDependenciesOrder(sortedCoreExtensions); resolvedExtensions.addAll(coreExtensionAwareExtensions); return resolvedExtensions; } private List<MuleCoreExtension> resolveCoreExtensionDependenciesOrder(List<MuleCoreExtension> sortedCoreExtensions) { List<MuleCoreExtension> unresolvedExtensions = new LinkedList<>(sortedCoreExtensions); List<MuleCoreExtension> resolvedExtensions = new LinkedList<>(); boolean continueResolution = true; while (continueResolution) { int initialResolvedCount = resolvedExtensions.size(); List<MuleCoreExtension> pendingUnresolvedExtensions = new LinkedList<>(); for (MuleCoreExtension muleCoreExtension : unresolvedExtensions) { if (isResolvedCoreExtension(muleCoreExtension, resolvedExtensions)) { resolvedExtensions.add(muleCoreExtension); } else { pendingUnresolvedExtensions.add(muleCoreExtension); } } // Will try to resolve the extensions that are still unresolved unresolvedExtensions = pendingUnresolvedExtensions; continueResolution = resolvedExtensions.size() > initialResolvedCount; } if (unresolvedExtensions.size() != 0) { throw new UnresolveableDependencyException("Unable to resolve core extension dependencies: " + unresolvedExtensions); } return resolvedExtensions; } private boolean isResolvedCoreExtension(MuleCoreExtension muleCoreExtension, List<MuleCoreExtension> resolvedExtensions) { final List<LinkedMuleCoreExtensionDependency> dependencies = dependencyDiscoverer.findDependencies(muleCoreExtension); boolean resolvedCoreExtension = dependencies.size() == 0; if (!resolvedCoreExtension && satisfiedDependencies(dependencies, resolvedExtensions)) { injectDependencies(muleCoreExtension, resolvedExtensions, dependencies); resolvedCoreExtension = true; } return resolvedCoreExtension; } private List<MuleCoreExtension> findCoreExtensionAwareExtensions(List<MuleCoreExtension> sortedCoreExtensions) { List<MuleCoreExtension> coreExtensionAwareExtensions = new LinkedList<>(); for (MuleCoreExtension muleCoreExtension : sortedCoreExtensions) { if (muleCoreExtension instanceof CoreExtensionsAware) { final List<LinkedMuleCoreExtensionDependency> dependencies = dependencyDiscoverer.findDependencies(muleCoreExtension); if (dependencies.isEmpty()) { coreExtensionAwareExtensions.add(muleCoreExtension); } else { throw new IllegalDependencyInjectionException("A class cannot implement CoreExtensionAware when is also using MuleCoreExtensionDependency"); } } } return coreExtensionAwareExtensions; } private void sortCoreExtensionsByName(List<MuleCoreExtension> coreExtensionAwareExtensions1) { Collections.sort(coreExtensionAwareExtensions1, new Comparator<MuleCoreExtension>() { @Override public int compare(MuleCoreExtension coreExtension1, MuleCoreExtension coreExtension2) { return coreExtension1.getName().compareTo(coreExtension2.getName()); } }); } private void injectDependencies(MuleCoreExtension muleCoreExtension, List<MuleCoreExtension> resolvedExtensions, List<LinkedMuleCoreExtensionDependency> dependencies) { for (LinkedMuleCoreExtensionDependency linkedMuleCoreExtensionDependency : dependencies) { final MuleCoreExtension dependencyInstance = findDependencyInstance(resolvedExtensions, linkedMuleCoreExtensionDependency.getDependencyClass()); try { linkedMuleCoreExtensionDependency.getDependantMethod().invoke(muleCoreExtension, new Object[] {dependencyInstance}); } catch (Exception e) { throw new MuleRuntimeException(e); } } } private MuleCoreExtension findDependencyInstance(List<MuleCoreExtension> resolvedExtensions, Class<? extends MuleCoreExtension> dependencyClass) { for (MuleCoreExtension coreExtension : resolvedExtensions) { if (dependencyClass.isAssignableFrom(coreExtension.getClass())) { return coreExtension; } } throw new IllegalArgumentException("Unable to find an instance for " + dependencyClass); } private boolean satisfiedDependencies(List<LinkedMuleCoreExtensionDependency> dependencies, List<MuleCoreExtension> resolvedExtensions) { for (LinkedMuleCoreExtensionDependency dependency : dependencies) { boolean isResolved = false; for (MuleCoreExtension resolved : resolvedExtensions) { if (dependency.getDependencyClass().isAssignableFrom(resolved.getClass())) { isResolved = true; } } if (!isResolved) { return false; } } return true; } }