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.web.page;
021
022import java.util.Arrays;
023import java.util.LinkedHashSet;
024import java.util.Set;
025import java.util.stream.Collectors;
026import java.util.stream.Stream;
027import javax.annotation.CheckForNull;
028
029import static java.lang.String.format;
030import static java.util.Objects.requireNonNull;
031import static org.sonar.api.web.page.Page.Scope.COMPONENT;
032import static org.sonar.api.web.page.Page.Scope.GLOBAL;
033
034/**
035 * @see PageDefinition
036 * @since 6.3
037 */
038public final class Page {
039  private final String key;
040  private final String name;
041  private final boolean isAdmin;
042  private final Scope scope;
043  private final Set<Qualifier> qualifiers;
044
045  private Page(Builder builder) {
046    this.key = builder.key;
047    this.name = builder.name;
048    this.qualifiers = Stream.of(builder.qualifiers).sorted().collect(Collectors.toCollection(LinkedHashSet::new));
049    this.isAdmin = builder.isAdmin;
050    this.scope = builder.scope;
051  }
052
053  public static Builder builder(String key) {
054    return new Builder(key);
055  }
056
057  public String getKey() {
058    return key;
059  }
060
061  public String getName() {
062    return name;
063  }
064
065  public Set<Qualifier> getComponentQualifiers() {
066    return qualifiers;
067  }
068
069  public boolean isAdmin() {
070    return isAdmin;
071  }
072
073  public Scope getScope() {
074    return scope;
075  }
076
077  public enum Scope {
078    GLOBAL, ORGANIZATION, COMPONENT
079  }
080
081  public enum Qualifier {
082    PROJECT(org.sonar.api.resources.Qualifiers.PROJECT),
083    MODULE(org.sonar.api.resources.Qualifiers.MODULE),
084    APP(org.sonar.api.resources.Qualifiers.APP),
085    VIEW(org.sonar.api.resources.Qualifiers.VIEW),
086    SUB_VIEW(org.sonar.api.resources.Qualifiers.SUBVIEW);
087
088    private final String key;
089
090    Qualifier(String key) {
091      this.key = key;
092    }
093
094    @CheckForNull
095    public static Qualifier fromKey(String key) {
096      return Arrays.stream(values())
097        .filter(qualifier -> qualifier.key.equals(key))
098        .findAny()
099        .orElse(null);
100    }
101
102    public String getKey() {
103      return key;
104    }
105  }
106
107  public static class Builder {
108    private final String key;
109    private String name;
110    private boolean isAdmin = false;
111    private Scope scope = GLOBAL;
112    private Qualifier[] qualifiers = new Qualifier[] {};
113
114    /**
115     * @param key It must respect the format plugin_key/page_identifier. Example: <code>my_plugin/my_page</code>
116     */
117    private Builder(String key) {
118      this.key = requireNonNull(key, "Key must not be null");
119    }
120
121    /**
122     * Page name displayed in the UI. Mandatory.
123     */
124    public Builder setName(String name) {
125      this.name = name;
126      return this;
127    }
128
129    /**
130     * if set to true, display the page in the administration section, depending on the scope
131     */
132    public Builder setAdmin(boolean admin) {
133      this.isAdmin = admin;
134      return this;
135    }
136
137    /**
138     * Define where the page is displayed, either in the global menu or in a component page
139     * @param scope - default is GLOBAL
140     */
141    public Builder setScope(Scope scope) {
142      this.scope = requireNonNull(scope, "Scope must not be null");
143      return this;
144    }
145
146    /**
147     * Define the components where the page is displayed. If set, {@link #setScope(Scope)} must be set to COMPONENT
148     * @see Qualifier
149     */
150    public Builder setComponentQualifiers(Qualifier... qualifiers) {
151      this.qualifiers = requireNonNull(qualifiers);
152      return this;
153    }
154
155    public Page build() {
156      if (key == null || key.isEmpty()) {
157        throw new IllegalArgumentException("Key must not be empty");
158      }
159      if (name == null || name.isEmpty()) {
160        throw new IllegalArgumentException("Name must be defined and not empty");
161      }
162      if (qualifiers.length > 0 && !COMPONENT.equals(scope)) {
163        throw new IllegalArgumentException(format("The scope must be '%s' when component qualifiers are provided", COMPONENT));
164      }
165      if (qualifiers.length == 0 && COMPONENT.equals(scope)) {
166        qualifiers = Qualifier.values();
167      }
168
169      return new Page(this);
170    }
171  }
172}