提交 d44b7981 编写于 作者: wu-sheng's avatar wu-sheng

Support cycle module dependencies check. Trigger exception when happen. @peng-yongsheng

org.skywalking.apm.collector.core.module.CycleDependencyException: Exist cycle module dependencies in
Test[provider=org.skywalking.apm.collector.core.module.TestModuleProvider]
BaseA[provider=org.skywalking.apm.collector.core.module.ModuleAProvider]
上级 e3e06ec3
...@@ -46,7 +46,7 @@ public final class Graph<INPUT> { ...@@ -46,7 +46,7 @@ public final class Graph<INPUT> {
void checkForNewNode(Node node) { void checkForNewNode(Node node) {
int nodeId = node.getHandler().id(); int nodeId = node.getHandler().id();
if (nodeIndex.containsKey(nodeId)) { if (nodeIndex.containsKey(nodeId)) {
throw new PotentialAcyclicGraphException("handler=" throw new PotentialCyclicGraphException("handler="
+ node.getHandler().getClass().getName() + node.getHandler().getClass().getName()
+ " already exists in graph[" + id + "】"); + " already exists in graph[" + id + "】");
} }
......
...@@ -21,8 +21,8 @@ package org.skywalking.apm.collector.core.graph; ...@@ -21,8 +21,8 @@ package org.skywalking.apm.collector.core.graph;
/** /**
* @author wusheng * @author wusheng
*/ */
public class PotentialAcyclicGraphException extends RuntimeException { public class PotentialCyclicGraphException extends RuntimeException {
public PotentialAcyclicGraphException(String message) { public PotentialCyclicGraphException(String message) {
super(message); super(message);
} }
} }
/*
* Copyright 2017, OpenSkywalking Organization All rights reserved.
*
* 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.
*
* Project repository: https://github.com/OpenSkywalking/skywalking
*/
package org.skywalking.apm.collector.core.module;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.skywalking.apm.collector.core.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author wu-sheng
*/
public class BootstrapFlow {
private final Logger logger = LoggerFactory.getLogger(BootstrapFlow.class);
private Map<String, Module> loadedModules;
private ApplicationConfiguration applicationConfiguration;
private List<ModuleProvider> startupSequence;
public BootstrapFlow(Map<String, Module> loadedModules,
ApplicationConfiguration applicationConfiguration) throws CycleDependencyException {
this.loadedModules = loadedModules;
this.applicationConfiguration = applicationConfiguration;
startupSequence = new LinkedList<>();
makeSequence();
}
void start(ModuleManager moduleManager,
ApplicationConfiguration configuration) throws ProviderNotFoundException, ModuleNotFoundException, ServiceNotProvidedException {
for (ModuleProvider provider : startupSequence) {
String[] requiredModules = provider.requiredModules();
if (requiredModules != null) {
for (String module : requiredModules) {
if (!moduleManager.has(module)) {
throw new ModuleNotFoundException(module + " is required by " + provider.getModuleName()
+ "." + provider.name() + ", but not found.");
}
}
}
logger.info("start the provider {} in {} module.", provider.name(), provider.getModuleName());
provider.start(configuration.getModuleConfiguration(provider.getModuleName()).getProviderConfiguration(provider.name()));
provider.requiredCheck(provider.getModule().services());
}
}
void notifyAfterCompleted() throws ProviderNotFoundException, ModuleNotFoundException, ServiceNotProvidedException {
for (ModuleProvider provider : startupSequence) {
provider.notifyAfterCompleted();
}
}
private void makeSequence() throws CycleDependencyException {
List<ModuleProvider> allProviders = new ArrayList<>();
loadedModules.forEach((moduleName, module) -> {
module.providers().forEach(provider -> {
allProviders.add(provider);
});
});
while (true) {
int numOfToBeSequenced = allProviders.size();
for (int i = 0; i < allProviders.size(); i++) {
ModuleProvider provider = allProviders.get(i);
String[] requiredModules = provider.requiredModules();
if (CollectionUtils.isNotEmpty(requiredModules)) {
boolean isAllRequiredModuleStarted = true;
for (String module : requiredModules) {
// find module in all ready existed startupSequence
boolean exist = false;
for (ModuleProvider moduleProvider : startupSequence) {
if (moduleProvider.getModuleName().equals(module)) {
exist = true;
break;
}
}
if (!exist) {
isAllRequiredModuleStarted = false;
break;
}
}
if (isAllRequiredModuleStarted) {
startupSequence.add(provider);
allProviders.remove(i);
}
} else {
startupSequence.add(provider);
allProviders.remove(i);
}
}
if (numOfToBeSequenced == allProviders.size()) {
StringBuilder unsequencedProviders = new StringBuilder();
allProviders.forEach(provider -> {
unsequencedProviders.append(provider.getModuleName()).append("[provider=").append(provider.getClass().getName()).append("]\n");
});
throw new CycleDependencyException("Exist cycle module dependencies in \n" + unsequencedProviders.substring(0, unsequencedProviders.length() - 1));
}
if (allProviders.size() == 0) {
break;
}
}
}
}
/*
* Copyright 2017, OpenSkywalking Organization All rights reserved.
*
* 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.
*
* Project repository: https://github.com/OpenSkywalking/skywalking
*/
package org.skywalking.apm.collector.core.module;
/**
* @author wu-sheng
*/
public class CycleDependencyException extends RuntimeException {
public CycleDependencyException(String message) {
super(message);
}
}
...@@ -87,45 +87,15 @@ public abstract class Module { ...@@ -87,45 +87,15 @@ public abstract class Module {
} }
} }
void start(ModuleManager moduleManager,
ApplicationConfiguration.ModuleConfiguration configuration) throws ProviderNotFoundException, ModuleNotFoundException, ServiceNotProvidedException {
for (ModuleProvider provider : loadedProviders) {
String[] requiredModules = provider.requiredModules();
if (requiredModules != null) {
for (String module : requiredModules) {
if (!moduleManager.has(module)) {
throw new ModuleNotFoundException(module + " is required by " + name() + ", but not found.");
}
}
}
logger.info("start the provider {} in {} module.", provider.name(), provider.module().getName());
provider.start(configuration.getProviderConfiguration(provider.name()));
provider.requiredCheck(services());
}
}
void notifyAfterCompleted() throws ProviderNotFoundException, ModuleNotFoundException, ServiceNotProvidedException {
for (ModuleProvider provider : loadedProviders) {
provider.notifyAfterCompleted();
}
}
/** /**
* @return providers of this module * @return providers of this module
*/ */
final List<ModuleProvider> providers() throws ProviderNotFoundException { final List<ModuleProvider> providers() {
if (loadedProviders.size() == 0) {
throw new ProviderNotFoundException(this.name() + " module no provider exists.");
}
return loadedProviders; return loadedProviders;
} }
final ModuleProvider provider() throws ProviderNotFoundException, DuplicateProviderException { final ModuleProvider provider() throws ProviderNotFoundException, DuplicateProviderException {
if (loadedProviders.size() == 0) { if (loadedProviders.size() > 1) {
throw new ProviderNotFoundException(this.name() + " module no provider exists.");
} else if (loadedProviders.size() > 1) {
throw new DuplicateProviderException(this.name() + " module exist " + loadedProviders.size() + " providers"); throw new DuplicateProviderException(this.name() + " module exist " + loadedProviders.size() + " providers");
} }
......
...@@ -39,7 +39,7 @@ public class ModuleManager { ...@@ -39,7 +39,7 @@ public class ModuleManager {
* @param applicationConfiguration * @param applicationConfiguration
*/ */
public void init( public void init(
ApplicationConfiguration applicationConfiguration) throws ModuleNotFoundException, ProviderNotFoundException, ServiceNotProvidedException { ApplicationConfiguration applicationConfiguration) throws ModuleNotFoundException, ProviderNotFoundException, ServiceNotProvidedException, CycleDependencyException {
String[] moduleNames = applicationConfiguration.moduleList(); String[] moduleNames = applicationConfiguration.moduleList();
ServiceLoader<Module> moduleServiceLoader = ServiceLoader.load(Module.class); ServiceLoader<Module> moduleServiceLoader = ServiceLoader.load(Module.class);
LinkedList<String> moduleList = new LinkedList(Arrays.asList(moduleNames)); LinkedList<String> moduleList = new LinkedList(Arrays.asList(moduleNames));
...@@ -65,13 +65,10 @@ public class ModuleManager { ...@@ -65,13 +65,10 @@ public class ModuleManager {
throw new ModuleNotFoundException(moduleList.toString() + " missing."); throw new ModuleNotFoundException(moduleList.toString() + " missing.");
} }
for (Module module : loadedModules.values()) { BootstrapFlow bootstrapFlow = new BootstrapFlow(loadedModules, applicationConfiguration);
module.start(this, applicationConfiguration.getModuleConfiguration(module.name()));
}
for (Module module : loadedModules.values()) { bootstrapFlow.start(this, applicationConfiguration);
module.notifyAfterCompleted(); bootstrapFlow.notifyAfterCompleted();
}
} }
public boolean has(String moduleName) { public boolean has(String moduleName) {
......
...@@ -133,4 +133,12 @@ public abstract class ModuleProvider { ...@@ -133,4 +133,12 @@ public abstract class ModuleProvider {
throw new ServiceNotProvidedException("Service " + serviceType.getName() + " should not be provided, based on module define."); throw new ServiceNotProvidedException("Service " + serviceType.getName() + " should not be provided, based on module define.");
} }
Module getModule() {
return module;
}
String getModuleName() {
return module.name();
}
} }
...@@ -75,7 +75,7 @@ public class GraphManagerTest { ...@@ -75,7 +75,7 @@ public class GraphManagerTest {
Assert.assertEquals(expected, output); Assert.assertEquals(expected, output);
} }
@Test(expected = PotentialAcyclicGraphException.class) @Test(expected = PotentialCyclicGraphException.class)
public void testPotentialAcyclicGraph() { public void testPotentialAcyclicGraph() {
Graph<String> testGraph = GraphManager.INSTANCE.createIfAbsent(3, String.class); Graph<String> testGraph = GraphManager.INSTANCE.createIfAbsent(3, String.class);
Node<String, String> node = testGraph.addNode(new Node1Processor()); Node<String, String> node = testGraph.addNode(new Node1Processor());
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册