1b5840353SAdam Hornáček /* 2b5840353SAdam Hornáček * CDDL HEADER START 3b5840353SAdam Hornáček * 4b5840353SAdam Hornáček * The contents of this file are subject to the terms of the 5b5840353SAdam Hornáček * Common Development and Distribution License (the "License"). 6b5840353SAdam Hornáček * You may not use this file except in compliance with the License. 7b5840353SAdam Hornáček * 8b5840353SAdam Hornáček * See LICENSE.txt included in this distribution for the specific 9b5840353SAdam Hornáček * language governing permissions and limitations under the License. 10b5840353SAdam Hornáček * 11b5840353SAdam Hornáček * When distributing Covered Code, include this CDDL HEADER in each 12b5840353SAdam Hornáček * file and include the License file at LICENSE.txt. 13b5840353SAdam Hornáček * If applicable, add the following below this CDDL HEADER, with the 14b5840353SAdam Hornáček * fields enclosed by brackets "[]" replaced with your own identifying 15b5840353SAdam Hornáček * information: Portions Copyright [yyyy] [name of copyright owner] 16b5840353SAdam Hornáček * 17b5840353SAdam Hornáček * CDDL HEADER END 18b5840353SAdam Hornáček */ 19b5840353SAdam Hornáček 20b5840353SAdam Hornáček /* 21*c6f0939bSAdam Hornacek * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. 2252dccac1SChris Fraire * Portions Copyright (c) 2018, Chris Fraire <cfraire@me.com>. 23b5840353SAdam Hornáček */ 249805b761SAdam Hornáček package org.opengrok.indexer.configuration; 25b5840353SAdam Hornáček 26b5840353SAdam Hornáček import java.util.Locale; 27b5840353SAdam Hornáček import java.util.Set; 28b5840353SAdam Hornáček import java.util.TreeSet; 29b5840353SAdam Hornáček import java.util.regex.Pattern; 30b5840353SAdam Hornáček import java.util.regex.PatternSyntaxException; 319805b761SAdam Hornáček import org.opengrok.indexer.util.ClassUtil; 32b5840353SAdam Hornáček 33b5840353SAdam Hornáček /** 34b5840353SAdam Hornáček * Placeholder for the information about subgroups of projects and repositories. 35b5840353SAdam Hornáček * 36b5840353SAdam Hornáček * Supports natural ordering based on case insensitive group names. 37b5840353SAdam Hornáček * 38b5840353SAdam Hornáček * @author Krystof Tulinger 39b5840353SAdam Hornáček * @version $Revision$ 40b5840353SAdam Hornáček */ 41b5840353SAdam Hornáček public class Group implements Comparable<Group>, Nameable { 42b5840353SAdam Hornáček 43b5840353SAdam Hornáček static { 44b5840353SAdam Hornáček ClassUtil.remarkTransientFields(Group.class); 45b5840353SAdam Hornáček } 46b5840353SAdam Hornáček 47b5840353SAdam Hornáček private String name; 48b5840353SAdam Hornáček /** 49b5840353SAdam Hornáček * Group regexp pattern. 50b5840353SAdam Hornáček * 51b5840353SAdam Hornáček * No project matches the empty pattern of "" however this group can still 52b5840353SAdam Hornáček * be used as a superior group for other groups (without duplicating the 53b5840353SAdam Hornáček * projects). 54b5840353SAdam Hornáček */ 55b5840353SAdam Hornáček private String pattern = ""; 56b5840353SAdam Hornáček /** 57b5840353SAdam Hornáček * Compiled group pattern. 58b5840353SAdam Hornáček * 59b5840353SAdam Hornáček * We set up the empty compiled pattern by default to "()" to reduce code 60b5840353SAdam Hornáček * complexity when performing a match for a group without a pattern. 61b5840353SAdam Hornáček * 62b5840353SAdam Hornáček * This pattern is updated whenever the string pattern {@link #pattern} is 63b5840353SAdam Hornáček * updated. 64b5840353SAdam Hornáček * 65b5840353SAdam Hornáček * @see #setPattern(String) 66b5840353SAdam Hornáček */ 67b5840353SAdam Hornáček private Pattern compiledPattern = Pattern.compile("()"); 68b5840353SAdam Hornáček private Group parent; 69b5840353SAdam Hornáček private Set<Group> subgroups = new TreeSet<>(); 70b5840353SAdam Hornáček 71b5840353SAdam Hornáček private transient int flag; 72b5840353SAdam Hornáček private transient Set<Group> descendants = new TreeSet<>(); 73b5840353SAdam Hornáček private transient Set<Project> projects = new TreeSet<>(); 74b5840353SAdam Hornáček private transient Set<Project> repositories = new TreeSet<>(); 75b5840353SAdam Hornáček private transient Set<Group> parents; 76b5840353SAdam Hornáček 77b5840353SAdam Hornáček /** 78b5840353SAdam Hornáček * No-arg constructor is needed for deserialization. 79b5840353SAdam Hornáček */ Group()80b5840353SAdam Hornáček public Group() { 81b5840353SAdam Hornáček } 82b5840353SAdam Hornáček Group(String name)83b5840353SAdam Hornáček public Group(String name) { 84b5840353SAdam Hornáček this(name, ""); 85b5840353SAdam Hornáček } 86b5840353SAdam Hornáček Group(String name, String pattern)87b5840353SAdam Hornáček public Group(String name, String pattern) { 88b5840353SAdam Hornáček this.name = name; 89b5840353SAdam Hornáček this.setPattern(pattern); 90b5840353SAdam Hornáček } 91b5840353SAdam Hornáček getProjects()92b5840353SAdam Hornáček public Set<Project> getProjects() { 93b5840353SAdam Hornáček return projects; 94b5840353SAdam Hornáček } 95b5840353SAdam Hornáček addProject(Project p)96b5840353SAdam Hornáček public void addProject(Project p) { 97b5840353SAdam Hornáček this.projects.add(p); 98b5840353SAdam Hornáček } 99b5840353SAdam Hornáček addRepository(Project p)100b5840353SAdam Hornáček public void addRepository(Project p) { 101b5840353SAdam Hornáček this.repositories.add(p); 102b5840353SAdam Hornáček } 103b5840353SAdam Hornáček getDescendants()104b5840353SAdam Hornáček public Set<Group> getDescendants() { 105b5840353SAdam Hornáček return descendants; 106b5840353SAdam Hornáček } 107b5840353SAdam Hornáček setDescendants(Set<Group> descendants)108b5840353SAdam Hornáček public void setDescendants(Set<Group> descendants) { 109b5840353SAdam Hornáček this.descendants = descendants; 110b5840353SAdam Hornáček } 111b5840353SAdam Hornáček addDescendant(Group g)112b5840353SAdam Hornáček public void addDescendant(Group g) { 113b5840353SAdam Hornáček this.descendants.add(g); 114b5840353SAdam Hornáček } 115b5840353SAdam Hornáček removeDescendant(Group g)116b5840353SAdam Hornáček public void removeDescendant(Group g) { 117b5840353SAdam Hornáček this.descendants.remove(g); 118b5840353SAdam Hornáček } 119b5840353SAdam Hornáček getRepositories()120b5840353SAdam Hornáček public Set<Project> getRepositories() { 121b5840353SAdam Hornáček return repositories; 122b5840353SAdam Hornáček } 123b5840353SAdam Hornáček setSubgroups(Set<Group> subgroups)124b5840353SAdam Hornáček public void setSubgroups(Set<Group> subgroups) { 125b5840353SAdam Hornáček this.subgroups = subgroups; 126b5840353SAdam Hornáček } 127b5840353SAdam Hornáček setProjects(Set<Project> projects)128b5840353SAdam Hornáček public void setProjects(Set<Project> projects) { 129b5840353SAdam Hornáček this.projects = projects; 130b5840353SAdam Hornáček } 131b5840353SAdam Hornáček setRepositories(Set<Project> repositories)132b5840353SAdam Hornáček public void setRepositories(Set<Project> repositories) { 133b5840353SAdam Hornáček this.repositories = repositories; 134b5840353SAdam Hornáček } 135b5840353SAdam Hornáček getSubgroups()136b5840353SAdam Hornáček public Set<Group> getSubgroups() { 137b5840353SAdam Hornáček return subgroups; 138b5840353SAdam Hornáček } 139b5840353SAdam Hornáček addGroup(Group g)140b5840353SAdam Hornáček public void addGroup(Group g) { 141b5840353SAdam Hornáček g.setParent(this); 142b5840353SAdam Hornáček subgroups.add(g); 143b5840353SAdam Hornáček descendants.add(g); 144b5840353SAdam Hornáček } 145b5840353SAdam Hornáček getParents()146b5840353SAdam Hornáček public Set<Group> getParents() { 147b5840353SAdam Hornáček if (parents == null) { 148b5840353SAdam Hornáček parents = new TreeSet<>(); 149b5840353SAdam Hornáček Group tmp = parent; 150b5840353SAdam Hornáček while (tmp != null) { 151b5840353SAdam Hornáček parents.add(tmp); 152b5840353SAdam Hornáček tmp = tmp.getParent(); 153b5840353SAdam Hornáček } 154b5840353SAdam Hornáček } 155b5840353SAdam Hornáček return parents; 156b5840353SAdam Hornáček } 157b5840353SAdam Hornáček 158b5840353SAdam Hornáček /** 159b5840353SAdam Hornáček * Collect all related groups to this group. A related group is 160b5840353SAdam Hornáček * <ul> 161b5840353SAdam Hornáček * <li>any ancestor</li> 162b5840353SAdam Hornáček * <li>any subgroup</li> 163b5840353SAdam Hornáček * </ul> 164b5840353SAdam Hornáček * 165b5840353SAdam Hornáček * @return all collected related groups to this group 166b5840353SAdam Hornáček */ getRelatedGroups()167b5840353SAdam Hornáček public Set<Group> getRelatedGroups() { 168b5840353SAdam Hornáček Set<Group> groupsTmp = new TreeSet<>(); 169b5840353SAdam Hornáček groupsTmp.addAll(getDescendants()); 170b5840353SAdam Hornáček groupsTmp.addAll(getParents()); 171b5840353SAdam Hornáček return groupsTmp; 172b5840353SAdam Hornáček } 173b5840353SAdam Hornáček 174b5840353SAdam Hornáček /** 175b5840353SAdam Hornáček * Collect all group's projects and repositories included in this group and 176b5840353SAdam Hornáček * in any subgroup. 177b5840353SAdam Hornáček * 178b5840353SAdam Hornáček * @return all collected projects and repositories 179b5840353SAdam Hornáček */ getAllProjects()180b5840353SAdam Hornáček public Set<Project> getAllProjects() { 181b5840353SAdam Hornáček Set<Project> projectsTmp = new TreeSet<>(); 182*c6f0939bSAdam Hornacek projectsTmp.addAll(getRepositories()); 183*c6f0939bSAdam Hornacek projectsTmp.addAll(getProjects()); 184b5840353SAdam Hornáček for (Group grp : getDescendants()) { 185b5840353SAdam Hornáček projectsTmp.addAll(grp.getAllProjects()); 186b5840353SAdam Hornáček } 187b5840353SAdam Hornáček return projectsTmp; 188b5840353SAdam Hornáček } 189b5840353SAdam Hornáček getParent()190b5840353SAdam Hornáček public Group getParent() { 191b5840353SAdam Hornáček return parent; 192b5840353SAdam Hornáček } 193b5840353SAdam Hornáček setParent(Group parent)194b5840353SAdam Hornáček public void setParent(Group parent) { 195b5840353SAdam Hornáček this.parent = parent; 196b5840353SAdam Hornáček } 197b5840353SAdam Hornáček 198b5840353SAdam Hornáček @Override getName()199b5840353SAdam Hornáček public String getName() { 200b5840353SAdam Hornáček return name; 201b5840353SAdam Hornáček } 202b5840353SAdam Hornáček 203b5840353SAdam Hornáček @Override setName(String name)204b5840353SAdam Hornáček public void setName(String name) { 205b5840353SAdam Hornáček this.name = name; 206b5840353SAdam Hornáček } 207b5840353SAdam Hornáček getPattern()208b5840353SAdam Hornáček public String getPattern() { 209b5840353SAdam Hornáček return pattern; 210b5840353SAdam Hornáček } 211b5840353SAdam Hornáček 212b5840353SAdam Hornáček /** 213b5840353SAdam Hornáček * Set the group pattern. 214b5840353SAdam Hornáček * 215b5840353SAdam Hornáček * @param pattern the regexp pattern for this group 216b5840353SAdam Hornáček * @throws PatternSyntaxException when the pattern is invalid 217b5840353SAdam Hornáček */ setPattern(String pattern)218b5840353SAdam Hornáček public final void setPattern(String pattern) throws PatternSyntaxException { 219b5840353SAdam Hornáček this.compiledPattern = Pattern.compile("(" + pattern + ")"); 220b5840353SAdam Hornáček this.pattern = pattern; 221b5840353SAdam Hornáček } 222b5840353SAdam Hornáček getFlag()223b5840353SAdam Hornáček public int getFlag() { 224b5840353SAdam Hornáček return flag; 225b5840353SAdam Hornáček } 226b5840353SAdam Hornáček setFlag(int flag)227b5840353SAdam Hornáček public void setFlag(int flag) { 228b5840353SAdam Hornáček this.flag = flag; 229b5840353SAdam Hornáček } 230b5840353SAdam Hornáček 231b5840353SAdam Hornáček /** 232ff44f24aSAdam Hornáček * Test group for a match. 233b5840353SAdam Hornáček * 234b5840353SAdam Hornáček * @param p project 235b5840353SAdam Hornáček * @return true if project's description matches the group pattern 236b5840353SAdam Hornáček */ match(Project p)237b5840353SAdam Hornáček public boolean match(Project p) { 238b5840353SAdam Hornáček return compiledPattern.matcher(p.getName()).matches(); 239b5840353SAdam Hornáček } 240b5840353SAdam Hornáček 241b5840353SAdam Hornáček @Override compareTo(Group o)242b5840353SAdam Hornáček public int compareTo(Group o) { 24352dccac1SChris Fraire return getName().toUpperCase(Locale.ROOT).compareTo( 24452dccac1SChris Fraire o.getName().toUpperCase(Locale.ROOT)); 245b5840353SAdam Hornáček } 246b5840353SAdam Hornáček 247b5840353SAdam Hornáček @Override hashCode()248b5840353SAdam Hornáček public int hashCode() { 249b5840353SAdam Hornáček int hash = 3; 25052dccac1SChris Fraire hash = 41 * hash + (this.name == null ? 0 : 25152dccac1SChris Fraire this.name.toUpperCase(Locale.ROOT).hashCode()); 252b5840353SAdam Hornáček return hash; 253b5840353SAdam Hornáček } 254b5840353SAdam Hornáček 255b5840353SAdam Hornáček @Override equals(Object obj)256b5840353SAdam Hornáček public boolean equals(Object obj) { 257b5840353SAdam Hornáček if (this == obj) { 258b5840353SAdam Hornáček return true; 259b5840353SAdam Hornáček } 260b5840353SAdam Hornáček if (obj == null) { 261b5840353SAdam Hornáček return false; 262b5840353SAdam Hornáček } 263b5840353SAdam Hornáček if (getClass() != obj.getClass()) { 264b5840353SAdam Hornáček return false; 265b5840353SAdam Hornáček } 266b5840353SAdam Hornáček final Group other = (Group) obj; 26752dccac1SChris Fraire 26852dccac1SChris Fraire int numNull = (name == null ? 1 : 0) + (other.name == null ? 1 : 0); 26952dccac1SChris Fraire switch (numNull) { 27052dccac1SChris Fraire case 0: 27152dccac1SChris Fraire return name.toUpperCase(Locale.ROOT).equals( 27252dccac1SChris Fraire other.name.toUpperCase(Locale.ROOT)); 27352dccac1SChris Fraire case 1: 27452dccac1SChris Fraire return false; 27552dccac1SChris Fraire default: 27652dccac1SChris Fraire return true; 27752dccac1SChris Fraire } 278b5840353SAdam Hornáček } 279b5840353SAdam Hornáček 280b5840353SAdam Hornáček /** 281ff44f24aSAdam Hornáček * Returns group object by its name. 282b5840353SAdam Hornáček * 283b5840353SAdam Hornáček * @param name name of a group 284b5840353SAdam Hornáček * @return group that fits the name 285b5840353SAdam Hornáček */ getByName(String name)286b5840353SAdam Hornáček public static Group getByName(String name) { 287b5840353SAdam Hornáček Group ret = null; 288b5840353SAdam Hornáček RuntimeEnvironment env = RuntimeEnvironment.getInstance(); 289b5840353SAdam Hornáček if (env.hasGroups()) { 290b5840353SAdam Hornáček for (Group grp : env.getGroups()) { 291b5840353SAdam Hornáček if (name.equals(grp.getName())) { 292b5840353SAdam Hornáček ret = grp; 293b5840353SAdam Hornáček } 294b5840353SAdam Hornáček } 295b5840353SAdam Hornáček } 296b5840353SAdam Hornáček return ret; 297b5840353SAdam Hornáček } 298b5840353SAdam Hornáček 299b5840353SAdam Hornáček /** 300b5840353SAdam Hornáček * Reduce the group set to only those which match the given project based on 301b5840353SAdam Hornáček * the project's description. 302b5840353SAdam Hornáček * 303b5840353SAdam Hornáček * @param project the project 304b5840353SAdam Hornáček * @param groups set of groups 305b5840353SAdam Hornáček * @return set of groups matching the project 306b5840353SAdam Hornáček */ matching(Project project, Set<Group> groups)307b5840353SAdam Hornáček public static Set<Group> matching(Project project, Set<Group> groups) { 308b5840353SAdam Hornáček Set<Group> copy = new TreeSet<>(groups); 309*c6f0939bSAdam Hornacek copy.removeIf(g -> !g.match(project)); 310b5840353SAdam Hornáček return copy; 311b5840353SAdam Hornáček } 312b5840353SAdam Hornáček } 313