/mycila-plugin/tags/mycila-plugin-1.4/src/main/java/com/mycila/plugin/spi/DefaultPluginResolver.java

http://mycila.googlecode.com/ · Java · 145 lines · 114 code · 13 blank · 18 comment · 31 complexity · 2369106a117e627317cd884f31409ce9 MD5 · raw file

  1. /**
  2. * Copyright (C) 2008 Mathieu Carbou <mathieu.carbou@gmail.com>
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.mycila.plugin.spi;
  17. import com.mycila.plugin.api.*;
  18. import static com.mycila.plugin.spi.PluginUtils.*;
  19. import org.jgrapht.DirectedGraph;
  20. import org.jgrapht.alg.CycleDetector;
  21. import org.jgrapht.graph.DefaultDirectedWeightedGraph;
  22. import org.jgrapht.graph.DefaultEdge;
  23. import org.jgrapht.traverse.TopologicalOrderIterator;
  24. import java.util.*;
  25. /**
  26. * @author Mathieu Carbou (mathieu.carbou@gmail.com)
  27. */
  28. final class DefaultPluginResolver<T extends Plugin> implements PluginResolver<T> {
  29. final PluginCache<T> cache;
  30. DefaultPluginResolver(PluginCache<T> cache) {
  31. this.cache = cache;
  32. }
  33. public SortedSet<PluginBinding<T>> getPlugins() {
  34. return Collections.unmodifiableSortedSet(new TreeSet<PluginBinding<T>>(cache.getBindings().values()));
  35. }
  36. public T getPlugin(String name) {
  37. PluginBinding<T> binding = cache.getBindings().get(name);
  38. if (binding == null) {
  39. throw new InexistingPluginException(name);
  40. }
  41. return binding.getPlugin();
  42. }
  43. public boolean contains(String name) {
  44. return getPlugins().contains(new Binding<T>(name));
  45. }
  46. public SortedMap<String, SortedSet<String>> getMissingDependenciesByPlugin() {
  47. SortedMap<String, SortedSet<String>> allMiss = new TreeMap<String, SortedSet<String>>();
  48. SortedSet<PluginBinding<T>> plugins = getPlugins();
  49. Set<String> loadedPlugins = new HashSet<String>(plugins.size());
  50. for (PluginBinding<T> plugin : plugins) {
  51. loadedPlugins.add(plugin.getName());
  52. }
  53. for (PluginBinding<T> binding : plugins) {
  54. SortedSet<String> pluginDependencies = new TreeSet<String>();
  55. if (binding.getPlugin().getBefore() != null) {
  56. for (String dep : binding.getPlugin().getBefore()) {
  57. if (!isEmpty(dep)) {
  58. pluginDependencies.add(dep);
  59. }
  60. }
  61. }
  62. if (binding.getPlugin().getAfter() != null) {
  63. for (String dep : binding.getPlugin().getAfter()) {
  64. if (!isEmpty(dep)) {
  65. pluginDependencies.add(dep);
  66. }
  67. }
  68. }
  69. pluginDependencies.removeAll(loadedPlugins);
  70. if (!pluginDependencies.isEmpty()) {
  71. allMiss.put(binding.getName(), Collections.unmodifiableSortedSet(pluginDependencies));
  72. }
  73. }
  74. return Collections.unmodifiableSortedMap(allMiss);
  75. }
  76. public SortedSet<String> getMissingDependencies() {
  77. SortedMap<String, SortedSet<String>> allMiss = getMissingDependenciesByPlugin();
  78. SortedSet<String> misses = new TreeSet<String>();
  79. for (SortedSet<String> plugins : allMiss.values()) {
  80. misses.addAll(plugins);
  81. }
  82. return Collections.unmodifiableSortedSet(misses);
  83. }
  84. public List<PluginBinding<T>> getResolvedPlugins() {
  85. List<String> names = getResolvedPluginsName();
  86. List<PluginBinding<T>> plugins = new ArrayList<PluginBinding<T>>(names.size());
  87. for (String name : names) {
  88. plugins.add(cache.getBindings().get(name));
  89. }
  90. return Collections.unmodifiableList(plugins);
  91. }
  92. public List<String> getResolvedPluginsName() {
  93. SortedSet<String> missingPlugins = getMissingDependencies();
  94. DirectedGraph<String, DefaultEdge> graph = new DefaultDirectedWeightedGraph<String, DefaultEdge>(DefaultEdge.class);
  95. for (PluginBinding<T> binding : getPlugins()) {
  96. graph.addVertex(binding.getName());
  97. if (binding.getPlugin().getBefore() != null) {
  98. for (String before : binding.getPlugin().getBefore()) {
  99. if (!isEmpty(before) && !missingPlugins.contains(before)) {
  100. graph.addVertex(before);
  101. graph.addEdge(before, binding.getName());
  102. }
  103. }
  104. }
  105. if (binding.getPlugin().getAfter() != null) {
  106. for (String after : binding.getPlugin().getAfter()) {
  107. if (!isEmpty(after) && !missingPlugins.contains(after)) {
  108. graph.addVertex(after);
  109. graph.addEdge(binding.getName(), after);
  110. }
  111. }
  112. }
  113. }
  114. if (graph.vertexSet().size() == 0) {
  115. return Collections.emptyList();
  116. }
  117. CycleDetector<String, DefaultEdge> detector = new CycleDetector<String, DefaultEdge>(graph);
  118. if (detector.detectCycles()) {
  119. SortedMap<String, Plugin> cyclics = new TreeMap<String, Plugin>();
  120. for (String pluginName : detector.findCycles()) {
  121. cyclics.put(pluginName, getPlugin(pluginName));
  122. }
  123. throw new CyclicDependencyException(cyclics);
  124. }
  125. List<String> order = new ArrayList<String>();
  126. Iterator<String> it = new TopologicalOrderIterator<String, DefaultEdge>(graph);
  127. while (it.hasNext()) {
  128. order.add(it.next());
  129. }
  130. return Collections.unmodifiableList(order);
  131. }
  132. }