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