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 */
020package org.sonar.server.ui;
021
022import com.google.common.collect.ImmutableSet;
023import com.google.common.collect.Maps;
024import org.apache.commons.lang.ArrayUtils;
025import org.apache.commons.lang.StringUtils;
026import org.apache.commons.lang.builder.CompareToBuilder;
027import org.apache.commons.lang.builder.EqualsBuilder;
028import org.apache.commons.lang.builder.ToStringBuilder;
029import org.sonar.api.utils.AnnotationUtils;
030import org.sonar.api.web.DefaultTab;
031import org.sonar.api.web.Description;
032import org.sonar.api.web.GwtPage;
033import org.sonar.api.web.NavigationSection;
034import org.sonar.api.web.RequiredMeasures;
035import org.sonar.api.web.ResourceLanguage;
036import org.sonar.api.web.ResourceQualifier;
037import org.sonar.api.web.ResourceScope;
038import org.sonar.api.web.UserRole;
039import org.sonar.api.web.View;
040import org.sonar.api.web.Widget;
041import org.sonar.api.web.WidgetCategory;
042import org.sonar.api.web.WidgetLayout;
043import org.sonar.api.web.WidgetLayoutType;
044import org.sonar.api.web.WidgetProperties;
045import org.sonar.api.web.WidgetProperty;
046import org.sonar.api.web.WidgetScope;
047
048import java.util.Collection;
049import java.util.Map;
050
051@SuppressWarnings("rawtypes")
052public class ViewProxy<V extends View> implements Comparable<ViewProxy> {
053
054  private V view;
055  private String[] sections = {NavigationSection.HOME};
056  private String[] userRoles = {};
057  private String[] resourceScopes = {};
058  private String[] resourceQualifiers = {};
059  private String[] resourceLanguages = {};
060  private String[] defaultForMetrics = {};
061  private String description = "";
062  private Map<String, WidgetProperty> widgetPropertiesByKey = Maps.newHashMap();
063  private String[] widgetCategories = {};
064  private WidgetLayoutType widgetLayout = WidgetLayoutType.DEFAULT;
065  private boolean isDefaultTab = false;
066  private boolean isWidget = false;
067  private boolean isGlobal = false;
068  private String[] mandatoryMeasures = {};
069  private String[] needOneOfMeasures = {};
070
071  public ViewProxy(final V view) {
072    this.view = view;
073
074    initUserRoles(view);
075    initSections(view);
076    initResourceScope(view);
077    initResourceQualifier(view);
078    initResourceLanguage(view);
079    initDefaultTabInfo(view);
080    initDescription(view);
081    initWidgetProperties(view);
082    initWidgetCategory(view);
083    initWidgetLayout(view);
084    initWidgetGlobal(view);
085    initRequiredMeasures(view);
086
087    isWidget = (view instanceof Widget);
088  }
089
090  private void initRequiredMeasures(V view) {
091    RequiredMeasures requiredMeasuresAnnotation = AnnotationUtils.getAnnotation(view, RequiredMeasures.class);
092    if (requiredMeasuresAnnotation != null) {
093      mandatoryMeasures = requiredMeasuresAnnotation.allOf();
094      needOneOfMeasures = requiredMeasuresAnnotation.anyOf();
095    }
096  }
097
098  private void initWidgetLayout(final V view) {
099    WidgetLayout layoutAnnotation = AnnotationUtils.getAnnotation(view, WidgetLayout.class);
100    if (layoutAnnotation != null) {
101      widgetLayout = layoutAnnotation.value();
102    }
103  }
104
105  private void initWidgetCategory(final V view) {
106    WidgetCategory categAnnotation = AnnotationUtils.getAnnotation(view, WidgetCategory.class);
107    if (categAnnotation != null) {
108      widgetCategories = categAnnotation.value();
109    }
110  }
111
112  private void initWidgetGlobal(V view) {
113    WidgetScope scopeAnnotation = AnnotationUtils.getAnnotation(view, WidgetScope.class);
114    if (scopeAnnotation != null) {
115      checkValidScope(view, scopeAnnotation);
116      isGlobal = ImmutableSet.copyOf(scopeAnnotation.value()).contains(WidgetScope.GLOBAL);
117    }
118  }
119
120  private static <V> void checkValidScope(V view, WidgetScope scopeAnnotation) {
121    for (String scope : scopeAnnotation.value()) {
122      if (!scope.equals(WidgetScope.PROJECT) && !scope.equalsIgnoreCase(WidgetScope.GLOBAL)) {
123        throw new IllegalArgumentException(String.format("Invalid widget scope %s for widget %s", scope, view.getClass().getSimpleName()));
124      }
125    }
126  }
127
128  private void initWidgetProperties(final V view) {
129    WidgetProperties propAnnotation = AnnotationUtils.getAnnotation(view, WidgetProperties.class);
130    if (propAnnotation != null) {
131      for (WidgetProperty property : propAnnotation.value()) {
132        widgetPropertiesByKey.put(property.key(), property);
133      }
134    }
135  }
136
137  private void initDescription(final V view) {
138    Description descriptionAnnotation = AnnotationUtils.getAnnotation(view, Description.class);
139    if (descriptionAnnotation != null) {
140      description = descriptionAnnotation.value();
141    }
142  }
143
144  private void initDefaultTabInfo(final V view) {
145    DefaultTab defaultTabAnnotation = AnnotationUtils.getAnnotation(view, DefaultTab.class);
146    if (defaultTabAnnotation != null) {
147      if (defaultTabAnnotation.metrics().length == 0) {
148        isDefaultTab = true;
149        defaultForMetrics = new String[0];
150
151      } else {
152        isDefaultTab = false;
153        defaultForMetrics = defaultTabAnnotation.metrics();
154      }
155    }
156  }
157
158  private void initResourceLanguage(final V view) {
159    ResourceLanguage languageAnnotation = AnnotationUtils.getAnnotation(view, ResourceLanguage.class);
160    if (languageAnnotation != null) {
161      resourceLanguages = languageAnnotation.value();
162    }
163  }
164
165  private void initResourceQualifier(final V view) {
166    ResourceQualifier qualifierAnnotation = AnnotationUtils.getAnnotation(view, ResourceQualifier.class);
167    if (qualifierAnnotation != null) {
168      resourceQualifiers = qualifierAnnotation.value();
169    }
170  }
171
172  private void initResourceScope(final V view) {
173    ResourceScope scopeAnnotation = AnnotationUtils.getAnnotation(view, ResourceScope.class);
174    if (scopeAnnotation != null) {
175      resourceScopes = scopeAnnotation.value();
176    }
177  }
178
179  private void initSections(final V view) {
180    NavigationSection sectionAnnotation = AnnotationUtils.getAnnotation(view, NavigationSection.class);
181    if (sectionAnnotation != null) {
182      sections = sectionAnnotation.value();
183    }
184  }
185
186  private void initUserRoles(final V view) {
187    UserRole userRoleAnnotation = AnnotationUtils.getAnnotation(view, UserRole.class);
188    if (userRoleAnnotation != null) {
189      userRoles = userRoleAnnotation.value();
190    }
191  }
192
193  public V getTarget() {
194    return view;
195  }
196
197  public String getId() {
198    return view.getId();
199  }
200
201  public boolean isController() {
202    String id = view.getId();
203    return id !=null && id.length()>0 && id.charAt(0)=='/';
204  }
205
206  public String getTitle() {
207    return view.getTitle();
208  }
209
210  public String getDescription() {
211    return description;
212  }
213
214  public Collection<WidgetProperty> getWidgetProperties() {
215    return widgetPropertiesByKey.values();
216  }
217
218  public WidgetProperty getWidgetProperty(String propertyKey) {
219    return widgetPropertiesByKey.get(propertyKey);
220  }
221
222  public String[] getWidgetCategories() {
223    return widgetCategories;
224  }
225
226  public String[] getSections() {
227    return sections;
228  }
229
230  public String[] getUserRoles() {
231    return userRoles;
232  }
233
234  public String[] getResourceScopes() {
235    return resourceScopes;
236  }
237
238  public String[] getResourceQualifiers() {
239    return resourceQualifiers;
240  }
241
242  public String[] getResourceLanguages() {
243    return resourceLanguages;
244  }
245
246  public boolean isDefaultTab() {
247    return isDefaultTab;
248  }
249
250  public String[] getDefaultTabForMetrics() {
251    return defaultForMetrics;
252  }
253
254  public boolean supportsMetric(String metricKey) {
255    return ArrayUtils.contains(defaultForMetrics, metricKey);
256  }
257  
258  public boolean acceptsAvailableMeasures(String[] availableMeasures) {
259    for (String mandatoryMeasure : mandatoryMeasures) {
260      if (!ArrayUtils.contains(availableMeasures, mandatoryMeasure)) {
261        return false;
262      }
263    }
264    if (needOneOfMeasures.length == 0) {
265      return true;
266    } else {
267      for (String neededMeasure : needOneOfMeasures) {
268        if (ArrayUtils.contains(availableMeasures, neededMeasure)) {
269          return true;
270        }
271      }
272      return false;
273    }
274  }
275
276  public boolean isWidget() {
277    return isWidget;
278  }
279
280  public boolean isGlobal() {
281    return isGlobal;
282  }
283
284  public boolean isGwt() {
285    return view instanceof GwtPage;
286  }
287
288  public WidgetLayoutType getWidgetLayout() {
289    return widgetLayout;
290  }
291
292  public boolean isEditable() {
293    return !widgetPropertiesByKey.isEmpty();
294  }
295
296  public boolean hasRequiredProperties() {
297    boolean requires = false;
298    for (WidgetProperty property : getWidgetProperties()) {
299      if (!property.optional() && StringUtils.isEmpty(property.defaultValue())) {
300        requires = true;
301      }
302    }
303    return requires;
304  }
305
306  @Override
307  public int hashCode() {
308    return getId().hashCode();
309  }
310
311  @Override
312  public boolean equals(Object obj) {
313    if (obj == null) {
314      return false;
315    }
316    if (obj == this) {
317      return true;
318    }
319    if (obj.getClass() != getClass()) {
320      return false;
321    }
322    ViewProxy rhs = (ViewProxy) obj;
323    return new EqualsBuilder()
324        .append(getId(), rhs.getId())
325        .isEquals();
326  }
327
328  @Override
329  public String toString() {
330    return new ToStringBuilder(this)
331        .append("id", view.getId())
332        .append("sections", sections)
333        .append("userRoles", userRoles)
334        .append("scopes", resourceScopes)
335        .append("qualifiers", resourceQualifiers)
336        .append("languages", resourceLanguages)
337        .append("metrics", defaultForMetrics)
338        .toString();
339
340  }
341
342  public int compareTo(ViewProxy other) {
343    return new CompareToBuilder()
344        .append(getTitle(), other.getTitle())
345        .append(getId(), other.getId())
346        .toComparison();
347
348  }
349}