001    /*
002     * SonarQube, open source software quality management tool.
003     * Copyright (C) 2008-2013 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * SonarQube 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     * SonarQube 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     */
020    package org.sonar.api.resources;
021    
022    import com.google.common.annotations.Beta;
023    import com.google.common.base.Preconditions;
024    import com.google.common.base.Strings;
025    import com.google.common.collect.Maps;
026    
027    import javax.annotation.Nullable;
028    import javax.annotation.concurrent.Immutable;
029    
030    import java.util.Map;
031    
032    /**
033     * <p>Experimental extension to declare types of resources.</p>
034     * <p>
035     * Since 3.0, ResourceType object can declare properties that give information about the capabilities of the
036     * resource type. Those properties may be used, of instance, to adapt the Web UI according to the type of
037     * the resource being displayed.
038     * <br>
039     * Currently, the following properties can be defined:
040     * </p>
041     * <ul>
042     * <li>"deletable": if set to "true", then this resource can be deleted/purged.</li>
043     * <li>"supportsMeasureFilters": if set to "true", then this resource can be displayed in measure filters</li>
044     * <li>"modifiable_history": if set to "true", then the history of this resource may be modified (deletion of snapshots, modification of events, ...)</li>
045     * <li>"updatable_key" (since 3.2): if set to "true", then it is possible to update the key of this resource</li>
046     * <li>"supportsGlobalDashboards" (since 3.2): if true, this resource can be displayed in global dashboards</li>
047     * <li>"hasRolePolicy" : if true, roles configuration is available in sidebar</li>
048     * <li>"comparable" (since 3.4) : if true, the resource can be compared to other resources</li>
049     * <li>"configurable" (since 3.6) : if true, the settings page can be displayed on the resource</li>
050     * </ul>
051     *
052     * @since 2.14
053     */
054    @Immutable
055    public class ResourceType {
056    
057      /**
058       * Builder used to create {@link ResourceType} objects.
059       */
060      public static class Builder {
061        private static final String SUPPORTS_MEASURE_FILTERS = "supportsMeasureFilters";
062        private String qualifier;
063        private String iconPath;
064        private boolean hasSourceCode = false;
065        private Map<String, String> properties = Maps.newHashMap();
066    
067        /**
068         * Creates a new {@link Builder}
069         *
070         * @param qualifier
071         */
072        public Builder(String qualifier) {
073          this.qualifier = qualifier;
074        }
075    
076        /**
077         * Relative path of the icon used to represent the resource type.
078         *
079         * @param iconPath path to icon, relative to context of web-application (e.g. "/images/q/DIR.png")
080         */
081        public Builder setIconPath(@Nullable String iconPath) {
082          this.iconPath = iconPath;
083          return this;
084        }
085    
086        /**
087         * @deprecated since 3.0. Use {@link #setProperty(String, String)} with "supportsMeasureFilters" set to "true".
088         */
089        @Deprecated
090        public Builder availableForFilters() {
091          setProperty(SUPPORTS_MEASURE_FILTERS, "true");
092          return this;
093        }
094    
095        /**
096         * Tells that the resources of this type will have source code.
097         */
098        public Builder hasSourceCode() {
099          this.hasSourceCode = true;
100          return this;
101        }
102    
103        /**
104         * Sets a property on the resource type. See the description of {@link ResourceType} class for more information.
105         *
106         * @since 3.0
107         */
108        public Builder setProperty(String key, String value) {
109          Preconditions.checkNotNull(key);
110          Preconditions.checkNotNull(value);
111          properties.put(key, value);
112    
113          // for backward-compatibility since version 3.4
114          if ("availableForFilters".equals(key)) {
115            properties.put(SUPPORTS_MEASURE_FILTERS, value);
116          }
117          return this;
118        }
119    
120        /**
121         * @since 3.2
122         */
123        public Builder setProperty(String key, boolean value) {
124          return setProperty(key, String.valueOf(value));
125        }
126    
127        /**
128         * Creates an instance of {@link ResourceType} based on all information given to the builder.
129         */
130        public ResourceType build() {
131          if (Strings.isNullOrEmpty(iconPath)) {
132            iconPath = "/images/q/" + qualifier + ".png";
133          }
134          return new ResourceType(this);
135        }
136      }
137    
138      /**
139       * Creates a new {@link Builder}
140       *
141       * @param qualifier
142       */
143      public static Builder builder(String qualifier) {
144        Preconditions.checkNotNull(qualifier);
145        Preconditions.checkArgument(qualifier.length() <= 10, "Qualifier is limited to 10 characters");
146        return new Builder(qualifier);
147      }
148    
149      private final String qualifier;
150      private final String iconPath;
151      private final boolean hasSourceCode;
152      private Map<String, String> properties;
153    
154      private ResourceType(Builder builder) {
155        this.qualifier = builder.qualifier;
156        this.iconPath = builder.iconPath;
157        this.hasSourceCode = builder.hasSourceCode;
158        this.properties = Maps.newHashMap(builder.properties);
159      }
160    
161      /**
162       * Qualifier is the unique key.
163       *
164       * @return the qualifier
165       */
166      public String getQualifier() {
167        return qualifier;
168      }
169    
170      /**
171       * Returns the relative path of the icon used to represent the resource type
172       *
173       * @return the relative path.
174       */
175      public String getIconPath() {
176        return iconPath;
177      }
178    
179      /**
180       * Tells whether resources of this type has source code or not.
181       *
182       * @return true if the type has source code
183       */
184      public boolean hasSourceCode() {
185        return hasSourceCode;
186      }
187    
188      public boolean hasProperty(String key) {
189        Preconditions.checkNotNull(key);
190        return properties.containsKey(key);
191      }
192    
193      /**
194       * Returns the value of the property for this resource type.
195       *
196       * @return the String value of the property, or NULL if the property hasn't been set.
197       * @since 3.0
198       */
199      public String getStringProperty(String key) {
200        Preconditions.checkNotNull(key);
201        return properties.get(key);
202      }
203    
204      /**
205       * Returns the value of the property for this resource type.
206       *
207       * @return the Boolean value of the property. If the property hasn't been set, False is returned.
208       * @since 3.0
209       */
210      public boolean getBooleanProperty(String key) {
211        Preconditions.checkNotNull(key);
212        String value = properties.get(key);
213        return value != null && Boolean.parseBoolean(value);
214      }
215    
216      @Override
217      public boolean equals(Object o) {
218        if (this == o) {
219          return true;
220        }
221        if (o == null || getClass() != o.getClass()) {
222          return false;
223        }
224    
225        ResourceType that = (ResourceType) o;
226        return qualifier.equals(that.qualifier);
227      }
228    
229      @Override
230      public int hashCode() {
231        return qualifier.hashCode();
232      }
233    
234      @Override
235      public String toString() {
236        return qualifier;
237      }
238    }