xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/configuration/Group.java (revision c6f0939b1c668e9f8e1e276424439c3106b3a029)
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