|
46 | 46 | import java.util.LinkedList; |
47 | 47 | import java.util.List; |
48 | 48 | import java.util.Map; |
| 49 | +import java.util.Objects; |
49 | 50 | import java.util.Set; |
50 | | -import java.util.TreeSet; |
| 51 | +import java.util.TreeMap; |
51 | 52 | import java.util.concurrent.ConcurrentHashMap; |
52 | 53 | import java.util.logging.Level; |
53 | 54 | import java.util.logging.Logger; |
@@ -134,7 +135,7 @@ public final class Configuration { |
134 | 135 | private boolean authorizationWatchdogEnabled; |
135 | 136 | private AuthorizationStack pluginStack; |
136 | 137 | private Map<String, Project> projects; // project name -> Project |
137 | | - private Set<Group> groups; |
| 138 | + private Map<String, Group> groups; // project name -> Group |
138 | 139 | private String sourceRoot; |
139 | 140 | private String dataRoot; |
140 | 141 | /** |
@@ -427,9 +428,9 @@ public int getIndexCheckTimeout() { |
427 | 428 | /** |
428 | 429 | * Set the index check timeout (performed by the webapp on startup) to a new value. |
429 | 430 | * |
430 | | - * @see org.opengrok.indexer.index.IndexCheck |
431 | 431 | * @param timeout the new value |
432 | 432 | * @throws IllegalArgumentException when the timeout is negative |
| 433 | + * @see org.opengrok.indexer.index.IndexCheck |
433 | 434 | */ |
434 | 435 | public void setIndexCheckTimeout(int timeout) throws IllegalArgumentException { |
435 | 436 | if (timeout < 0) { |
@@ -569,7 +570,7 @@ public Configuration() { |
569 | 570 | setFetchHistoryWhenNotInCache(true); |
570 | 571 | setFoldingEnabled(true); |
571 | 572 | setGenerateHtml(true); |
572 | | - setGroups(new TreeSet<>()); |
| 573 | + setGroups(new HashMap<>()); |
573 | 574 | setGroupsCollapseThreshold(4); |
574 | 575 | setHandleHistoryOfRenamedFiles(false); |
575 | 576 | setHistoryBasedReindex(true); |
@@ -636,6 +637,7 @@ public Map<String, String> getCmds() { |
636 | 637 | } |
637 | 638 |
|
638 | 639 | /** |
| 640 | + * @return int the current message limit |
639 | 641 | * @see org.opengrok.indexer.web.messages.MessagesContainer |
640 | 642 | * |
641 | 643 | * @return int the current message limit |
@@ -689,6 +691,7 @@ public void setCmds(Map<String, String> cmds) { |
689 | 691 |
|
690 | 692 | /** |
691 | 693 | * Gets the configuration's ctags command. Default is null. |
| 694 | + * |
692 | 695 | * @return the configured value |
693 | 696 | */ |
694 | 697 | public String getCtags() { |
@@ -898,24 +901,25 @@ public void setProjects(Map<String, Project> projects) { |
898 | 901 | } |
899 | 902 |
|
900 | 903 | /** |
901 | | - * Adds a group to the set. This is performed upon configuration parsing |
| 904 | + * Adds a group to the map. This is performed upon configuration parsing |
902 | 905 | * |
903 | 906 | * @param group group |
904 | | - * @throws IOException when group is not unique across the set |
| 907 | + * @throws IOException when group is not unique across the map |
905 | 908 | */ |
906 | 909 | public void addGroup(Group group) throws IOException { |
907 | | - if (!groups.add(group)) { |
| 910 | + if (groups.containsKey(group.getName())) { |
908 | 911 | throw new IOException( |
909 | 912 | String.format("Duplicate group name '%s' in configuration.", |
910 | 913 | group.getName())); |
911 | 914 | } |
| 915 | + groups.put(group.getName(), group); |
912 | 916 | } |
913 | 917 |
|
914 | | - public Set<Group> getGroups() { |
| 918 | + public Map<String, Group> getGroups() { |
915 | 919 | return groups; |
916 | 920 | } |
917 | 921 |
|
918 | | - public void setGroups(Set<Group> groups) { |
| 922 | + public void setGroups(Map<String, Group> groups) { |
919 | 923 | this.groups = groups; |
920 | 924 | } |
921 | 925 |
|
@@ -1541,24 +1545,30 @@ private static Configuration decodeObject(InputStream in) throws IOException { |
1541 | 1545 | // This ensures that when the configuration is reloaded then the set |
1542 | 1546 | // contains only root groups. Subgroups are discovered again |
1543 | 1547 | // as follows below |
1544 | | - conf.groups.removeIf(g -> g.getParent() != null); |
1545 | 1548 |
|
| 1549 | + List<Group> nonRootGroups = conf.groups.values().stream() |
| 1550 | + .filter(g -> Objects.nonNull(g.getParent())) |
| 1551 | + .collect(Collectors.toList()); |
| 1552 | + nonRootGroups.forEach(g -> { |
| 1553 | + conf.groups.remove(g.getName()); |
| 1554 | + } |
| 1555 | + ); |
1546 | 1556 | // Traversing subgroups and checking for duplicates, |
1547 | 1557 | // effectively transforms the group tree to a structure (Set) |
1548 | 1558 | // supporting an iterator. |
1549 | | - TreeSet<Group> copy = new TreeSet<>(); |
1550 | | - LinkedList<Group> stack = new LinkedList<>(conf.groups); |
| 1559 | + Map<String, Group> copy = new TreeMap<>(); |
| 1560 | + LinkedList<Group> stack = new LinkedList<>(conf.groups.values()); |
1551 | 1561 | while (!stack.isEmpty()) { |
1552 | 1562 | Group group = stack.pollFirst(); |
1553 | 1563 | stack.addAll(group.getSubgroups()); |
1554 | 1564 |
|
1555 | | - if (!copy.add(group)) { |
| 1565 | + if (copy.containsKey(group.getName())) { |
1556 | 1566 | throw new IOException( |
1557 | 1567 | String.format("Duplicate group name '%s' in configuration.", |
1558 | 1568 | group.getName())); |
1559 | 1569 | } |
1560 | | - |
1561 | | - // populate groups where the current group in in their subtree |
| 1570 | + copy.put(group.getName(), group); |
| 1571 | + // populate groups where the current group is in their subtree |
1562 | 1572 | Group tmp = group.getParent(); |
1563 | 1573 | while (tmp != null) { |
1564 | 1574 | tmp.addDescendant(group); |
|
0 commit comments