|
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