001/*
002 * SonarQube
003 * Copyright (C) 2009-2017 SonarSource SA
004 * mailto:info AT sonarsource DOT com
005 *
006 * This program is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019 */
020package org.sonar.api.resources;
021
022import com.google.common.annotations.Beta;
023import java.util.ArrayList;
024import java.util.Collection;
025import java.util.Collections;
026import java.util.LinkedHashMap;
027import java.util.LinkedHashSet;
028import java.util.List;
029import java.util.Map;
030import java.util.Objects;
031import java.util.Set;
032import java.util.function.Predicate;
033import java.util.stream.Collectors;
034import java.util.stream.Stream;
035import org.sonar.api.ce.ComputeEngineSide;
036import org.sonar.api.server.ServerSide;
037
038import static java.util.Collections.unmodifiableList;
039import static java.util.Collections.unmodifiableMap;
040import static java.util.Collections.unmodifiableSet;
041import static java.util.Objects.requireNonNull;
042
043/**
044 * @since 2.14
045 */
046@Beta
047@ServerSide
048@ComputeEngineSide
049public class ResourceTypes {
050
051  public static final Predicate<ResourceType> AVAILABLE_FOR_FILTERS = input -> input != null && input.getBooleanProperty("supportsMeasureFilters");
052
053  private final Map<String, ResourceTypeTree> treeByQualifier;
054  private final Map<String, ResourceType> typeByQualifier;
055  private final Collection<ResourceType> orderedTypes;
056  private final Collection<ResourceType> rootTypes;
057
058  public ResourceTypes() {
059    this(new ResourceTypeTree[0]);
060  }
061
062  public ResourceTypes(ResourceTypeTree[] trees) {
063    requireNonNull(trees);
064
065    Map<String, ResourceTypeTree> treeMap = new LinkedHashMap<>();
066    Map<String, ResourceType> typeMap = new LinkedHashMap<>();
067    Collection<ResourceType> rootsSet = new LinkedHashSet<>();
068
069    for (ResourceTypeTree tree : trees) {
070      rootsSet.add(tree.getRootType());
071      for (ResourceType type : tree.getTypes()) {
072        if (treeMap.containsKey(type.getQualifier())) {
073          throw new IllegalStateException("Qualifier " + type.getQualifier() + " is defined in several trees");
074        }
075        treeMap.put(type.getQualifier(), tree);
076        typeMap.put(type.getQualifier(), type);
077      }
078    }
079    treeByQualifier = unmodifiableMap(new LinkedHashMap<>(treeMap));
080    typeByQualifier = unmodifiableMap(new LinkedHashMap<>(typeMap));
081    rootTypes = unmodifiableList(new ArrayList<>(rootsSet));
082    orderedTypes = unmodifiableSet(orderedTypes(typeMap));
083  }
084
085  private static Set<ResourceType> orderedTypes(Map<String, ResourceType> typeByQualifier) {
086    Map<String, ResourceType> mutableTypesByQualifier = new LinkedHashMap<>(typeByQualifier);
087    ResourceType view = mutableTypesByQualifier.remove(Qualifiers.VIEW);
088    ResourceType subView = mutableTypesByQualifier.remove(Qualifiers.SUBVIEW);
089    ResourceType application = mutableTypesByQualifier.remove(Qualifiers.APP);
090
091    return Stream.concat(Stream.of(view, subView, application), mutableTypesByQualifier.values().stream())
092      .filter(Objects::nonNull)
093      .collect(Collectors.toCollection(LinkedHashSet::new));
094  }
095
096  public ResourceType get(String qualifier) {
097    ResourceType type = typeByQualifier.get(qualifier);
098    return type != null ? type : ResourceType.builder(qualifier).build();
099  }
100
101  public Collection<ResourceType> getAll() {
102    return typeByQualifier.values();
103  }
104
105  public Collection<ResourceType> getAllOrdered() {
106    return orderedTypes;
107  }
108
109  public Collection<ResourceType> getRoots() {
110    return rootTypes;
111  }
112
113  public Collection<ResourceType> getAll(Predicate<ResourceType> predicate) {
114    return typeByQualifier.values().stream()
115      .filter(predicate)
116      .collect(Collectors.toList());
117  }
118
119  public Collection<ResourceType> getAllWithPropertyKey(String propertyKey) {
120    return typeByQualifier.values()
121      .stream()
122      .filter(Objects::nonNull)
123      .filter(input -> input.hasProperty(propertyKey))
124      .collect(Collectors.toList());
125  }
126
127  public Collection<ResourceType> getAllWithPropertyValue(String propertyKey, String propertyValue) {
128    return typeByQualifier.values()
129      .stream()
130      .filter(Objects::nonNull)
131      .filter(input -> Objects.equals(propertyValue, input.getStringProperty(propertyKey)))
132      .collect(Collectors.toList());
133  }
134
135  public Collection<ResourceType> getAllWithPropertyValue(String propertyKey, boolean propertyValue) {
136    return typeByQualifier.values()
137      .stream()
138      .filter(Objects::nonNull)
139      .filter(input -> input.getBooleanProperty(propertyKey) == propertyValue)
140      .collect(Collectors.toList());
141  }
142
143  public List<String> getChildrenQualifiers(String qualifier) {
144    ResourceTypeTree tree = getTree(qualifier);
145    if (tree != null) {
146      return tree.getChildren(qualifier);
147    }
148    return Collections.emptyList();
149  }
150
151  public List<ResourceType> getChildren(String qualifier) {
152    return getChildrenQualifiers(qualifier)
153      .stream()
154      .map(typeByQualifier::get)
155      .collect(Collectors.toList());
156  }
157
158  public List<String> getLeavesQualifiers(String qualifier) {
159    ResourceTypeTree tree = getTree(qualifier);
160    if (tree != null) {
161      return tree.getLeaves();
162    }
163    return Collections.emptyList();
164  }
165
166  public ResourceTypeTree getTree(String qualifier) {
167    return treeByQualifier.get(qualifier);
168  }
169
170  public ResourceType getRoot(String qualifier) {
171    return getTree(qualifier).getRootType();
172  }
173
174}