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.Set;
024import java.util.stream.Collectors;
025import java.util.stream.Stream;
026import javax.annotation.CheckForNull;
027
028import static java.lang.String.format;
029import static java.util.Collections.unmodifiableSet;
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 = unmodifiableSet(Stream.of(builder.qualifiers).sorted().collect(Collectors.toSet()));
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    VIEW(org.sonar.api.resources.Qualifiers.VIEW),
085    SUB_VIEW(org.sonar.api.resources.Qualifiers.SUBVIEW);
086
087    private final String key;
088
089    Qualifier(String key) {
090      this.key = key;
091    }
092
093    @CheckForNull
094    public static Qualifier fromKey(String key) {
095      return Arrays.stream(values())
096        .filter(qualifier -> qualifier.key.equals(key))
097        .findAny()
098        .orElse(null);
099    }
100
101    public String getKey() {
102      return key;
103    }
104  }
105
106  public static class Builder {
107    private final String key;
108    private String name;
109    private boolean isAdmin = false;
110    private Scope scope = GLOBAL;
111    private Qualifier[] qualifiers = new Qualifier[] {};
112
113    /**
114     * @param key It must respect the format plugin_key/page_identifier. Example: <code>my_plugin/my_page</code>
115     */
116    private Builder(String key) {
117      this.key = requireNonNull(key, "Key must not be null");
118    }
119
120    /**
121     * Page name displayed in the UI. Mandatory.
122     */
123    public Builder setName(String name) {
124      this.name = name;
125      return this;
126    }
127
128    /**
129     * if set to true, display the page in the administration section, depending on the scope
130     */
131    public Builder setAdmin(boolean admin) {
132      this.isAdmin = admin;
133      return this;
134    }
135
136    /**
137     * Define where the page is displayed, either in the global menu or in a component page
138     * @param scope - default is GLOBAL
139     */
140    public Builder setScope(Scope scope) {
141      this.scope = requireNonNull(scope, "Scope must not be null");
142      return this;
143    }
144
145    /**
146     * Define the components where the page is displayed. If set, {@link #setScope(Scope)} must be set to COMPONENT
147     * @see Qualifier
148     */
149    public Builder setComponentQualifiers(Qualifier... qualifiers) {
150      this.qualifiers = requireNonNull(qualifiers);
151      return this;
152    }
153
154    public Page build() {
155      if (key == null || key.isEmpty()) {
156        throw new IllegalArgumentException("Key must not be empty");
157      }
158      if (name == null || name.isEmpty()) {
159        throw new IllegalArgumentException("Name must be defined and not empty");
160      }
161      if (qualifiers.length > 0 && !COMPONENT.equals(scope)) {
162        throw new IllegalArgumentException(format("The scope must be '%s' when component qualifiers are provided", COMPONENT));
163      }
164      if (qualifiers.length == 0 && COMPONENT.equals(scope)) {
165        qualifiers = Qualifier.values();
166      }
167
168      return new Page(this);
169    }
170  }
171}