001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2012 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar 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     * Sonar 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
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.api.resources;
021    
022    import java.util.Map;
023    
024    import javax.annotation.Nullable;
025    import javax.annotation.concurrent.Immutable;
026    
027    import com.google.common.annotations.Beta;
028    import com.google.common.base.Preconditions;
029    import com.google.common.base.Strings;
030    import com.google.common.collect.Maps;
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>"availableForFilters": if set to "true", then this resource can be displayed in the filters results</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     * </ul>
046     *
047     * @since 2.14
048     */
049    @Beta
050    @Immutable
051    public final class ResourceType {
052    
053      /**
054       * Builder used to create {@link ResourceType} objects.
055       */
056      public static class Builder {
057        private String qualifier;
058        private String iconPath;
059        private boolean hasSourceCode = false;
060        private Map<String, String> properties = Maps.newHashMap();
061    
062        /**
063         * Creates a new {@link Builder}
064         * @param qualifier
065         */
066        public Builder(String qualifier) {
067          this.qualifier = qualifier;
068        }
069    
070        /**
071         * Relative path of the icon used to represent the resource type.
072         * 
073         * @param iconPath path to icon, relative to context of web-application (e.g. "/images/q/DIR.png")
074         */
075        public Builder setIconPath(@Nullable String iconPath) {
076          this.iconPath = iconPath;
077          return this;
078        }
079    
080        /**
081         * @deprecated since 3.0. Use {@link #setProperty(String, String)} with "availableForFilters" set to "true".
082         */
083        @Deprecated
084        public Builder availableForFilters() {
085          setProperty("availableForFilters", "true");
086          return this;
087        }
088    
089        /**
090         * Tells that the resources of this type will have source code.
091         */
092        public Builder hasSourceCode() {
093          this.hasSourceCode = true;
094          return this;
095        }
096    
097        /**
098         * Sets a property on the resource type. See the description of {@link ResourceType} class for more information.
099         * 
100         * @since 3.0
101         */
102        public Builder setProperty(String key, String value) {
103          Preconditions.checkNotNull(key);
104          Preconditions.checkNotNull(value);
105          properties.put(key, value);
106          return this;
107        }
108    
109        /**
110         * Creates an instance of {@link ResourceType} based on all information given to the builder.
111         */
112        public ResourceType build() {
113          if (Strings.isNullOrEmpty(iconPath)) {
114            iconPath = "/images/q/" + qualifier + ".png";
115          }
116          return new ResourceType(this);
117        }
118      }
119    
120      /**
121       * Creates a new {@link Builder}
122       * @param qualifier
123       */
124      public static Builder builder(String qualifier) {
125        Preconditions.checkNotNull(qualifier);
126        Preconditions.checkArgument(qualifier.length() <= 10, "Qualifier is limited to 10 characters");
127        return new Builder(qualifier);
128      }
129    
130      private final String qualifier;
131      private final String iconPath;
132      private final boolean hasSourceCode;
133      private Map<String, String> properties;
134    
135      private ResourceType(Builder builder) {
136        this.qualifier = builder.qualifier;
137        this.iconPath = builder.iconPath;
138        this.hasSourceCode = builder.hasSourceCode;
139        this.properties = Maps.newHashMap(builder.properties);
140      }
141    
142      /**
143       * Qualifier is the unique key.
144       * 
145       * @return the qualifier
146       */
147      public String getQualifier() {
148        return qualifier;
149      }
150    
151      /**
152       * Returns the relative path of the icon used to represent the resource type
153       * 
154       * @return the relative path.
155       */
156      public String getIconPath() {
157        return iconPath;
158      }
159    
160      /**
161       * @deprecated since 3.0. Use {@link #getBooleanProperty(String)} with "availableForFilters".
162       */
163      @Deprecated
164      public boolean isAvailableForFilters() {
165        Boolean availableForFilters = getBooleanProperty("availableForFilters");
166        return availableForFilters == null ? false : availableForFilters.booleanValue();
167      }
168    
169      /**
170       * Tells whether resources of this type has source code or not.
171       * 
172       * @return true if the type has source code
173       */
174      public boolean hasSourceCode() {
175        return hasSourceCode;
176      }
177    
178      /**
179       * Returns the value of the property for this resource type.
180       * 
181       * @return the String value of the property, or NULL if the property hasn't been set.
182       * @since 3.0
183       */
184      public String getStringProperty(String key) {
185        Preconditions.checkNotNull(key);
186        return properties.get(key);
187      }
188    
189      /**
190       * Returns the value of the property for this resource type.
191       * 
192       * @return the Boolean value of the property. If the property hasn't been set, False is returned.
193       * @since 3.0
194       */
195      public Boolean getBooleanProperty(String key) {
196        Preconditions.checkNotNull(key);
197        return Boolean.valueOf(properties.get(key));
198      }
199    
200      @Override
201      public boolean equals(Object o) {
202        if (this == o) {
203          return true;
204        }
205        if (o == null || getClass() != o.getClass()) {
206          return false;
207        }
208    
209        ResourceType that = (ResourceType) o;
210        return qualifier.equals(that.qualifier);
211      }
212    
213      @Override
214      public int hashCode() {
215        return qualifier.hashCode();
216      }
217    }