/** * Process the 'digital' reaction in a way to obtain an ordered list of components, taking account * of their dependencies. * * @return Ordered list of comoponent's Ids. */ public List<String> proceed() { // ----- // 1.On vérifie si tous les composants définis par leurs ids existent final StringBuilder missing = new StringBuilder(); for (final DIComponentInfo componentInfo : diComponentInfos) { for (final DIDependency dependency : componentInfo.getDependencies()) { // Si une référence est requise // et qu'elle est absente, c'est qu'elle est manquante ! if (dependency.isRequired() && !allComponentInfos.contains(dependency.getName())) { missing .append(dependency) .append(" (referenced by " + componentInfo.getId() + ")") .append(", "); } } } if (missing.length() > 0) { throw new DIException( "Components not found :" + missing.toString() + "\n\tLoaded components : " + diComponentInfos); } // ----- // 2.On résout les dépendances final List<DIComponentInfo> unsorted = new ArrayList<>(diComponentInfos); // Niveaux de dépendances des composants // final List<List<String>> levels = new ArrayList<>(); final List<String> sorted = new ArrayList<>(); // . Par défaut on considére comme triés tous les parents // On va trier les nouveaux composants. while (!unsorted.isEmpty()) { final int countSorted = sorted.size(); for (final Iterator<DIComponentInfo> iterator = unsorted.iterator(); iterator.hasNext(); ) { final DIComponentInfo componentInfo = iterator.next(); final boolean solved = isSolved(componentInfo, parentComponentInfos, allComponentInfos, sorted); if (solved) { // Le composant est résolu // - On l'ajoute sa clé à la liste des clés de composants résolus // - On le supprime de la liste des composants à résoudre sorted.add(componentInfo.getId()); iterator.remove(); } } // Si lors d'une itération on ne fait rien c'est qu'il y a une dépendance cyclique if (countSorted == sorted.size()) { // On a une dépendance cyclique ! throw new DIException("Liste des composants non résolus :" + unsorted); } } // ----- // 3 On expose un liste de ids et non les composantInfos return Collections.unmodifiableList(sorted); }
private static boolean isSolved( final DIDependency dependency, final Set<String> parentComponentInfos, final Set<String> allComponentInfos, final List<String> sorted) { // Une dépendace est résolue si tous les ids concernés sont résolus. // Si la dépendance est déjà résolue et bien c'est bon on pass à la dépendances suivante if (dependency.isRequired()) { return parentComponentInfos.contains(dependency.getName()) || sorted.contains(dependency.getName()); } else if (dependency.isOption()) { // Si l'objet fait partie de la liste alors il doit être résolu. if (allComponentInfos.contains(dependency.getName())) { return sorted.contains(dependency.getName()); } // Sinon comme il est optionnel c'est ok. return true; } else if (dependency.isList()) { // Si l'objet fait partie de la liste alors il doit être résolu. for (final String id : allComponentInfos) { final boolean match = id.equals(dependency.getName()) || id.startsWith(dependency.getName() + '#'); if (match && !sorted.contains(id)) { // L'objet id fait partie de la liste return sorted.contains(id); } } return true; } throw new IllegalStateException(); }