001/* 002 * SonarQube 003 * Copyright (C) 2009-2016 SonarSource SA 004 * mailto:contact 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.config; 021 022import com.google.common.base.Strings; 023import java.util.ArrayList; 024import java.util.Arrays; 025import java.util.Collection; 026import java.util.HashMap; 027import java.util.Map; 028import javax.annotation.CheckForNull; 029import javax.annotation.Nullable; 030import org.apache.commons.lang.StringUtils; 031import org.sonar.api.CoreProperties; 032import org.sonar.api.Properties; 033import org.sonar.api.Property; 034import org.sonar.api.batch.ScannerSide; 035import org.sonar.api.ce.ComputeEngineSide; 036import org.sonar.api.server.ServerSide; 037import org.sonar.api.utils.AnnotationUtils; 038 039/** 040 * Metadata of all the properties declared by plugins 041 * 042 * @since 2.12 043 */ 044@ScannerSide 045@ServerSide 046@ComputeEngineSide 047public final class PropertyDefinitions { 048 049 private final Map<String, PropertyDefinition> definitions = new HashMap<>(); 050 private final Map<String, Category> categories = new HashMap<>(); 051 private final Map<String, SubCategory> subcategories = new HashMap<>(); 052 053 // deprecated key -> new key 054 private final Map<String, String> deprecatedKeys = new HashMap<>(); 055 056 public PropertyDefinitions(Object... components) { 057 if (components != null) { 058 addComponents(Arrays.asList(components)); 059 } 060 } 061 062 public PropertyDefinitions(Collection<PropertyDefinition> components) { 063 addComponents(components); 064 } 065 066 public PropertyDefinitions addComponents(Collection components) { 067 return addComponents(components, ""); 068 } 069 070 public PropertyDefinitions addComponents(Collection components, String defaultCategory) { 071 for (Object component : components) { 072 addComponent(component, defaultCategory); 073 } 074 return this; 075 } 076 077 public PropertyDefinitions addComponent(Object object) { 078 return addComponent(object, ""); 079 } 080 081 public PropertyDefinitions addComponent(Object component, String defaultCategory) { 082 addComponentFromAnnotationProperty(component, defaultCategory); 083 if (component instanceof PropertyDefinition) { 084 PropertyDefinition propertyDefinition = (PropertyDefinition) component; 085 add(propertyDefinition, defaultCategory); 086 } 087 return this; 088 } 089 090 private PropertyDefinitions addComponentFromAnnotationProperty(Object component, String defaultCategory) { 091 Properties annotations = AnnotationUtils.getAnnotation(component, Properties.class); 092 if (annotations != null) { 093 for (Property property : annotations.value()) { 094 addProperty(property, defaultCategory); 095 } 096 } 097 Property annotation = AnnotationUtils.getAnnotation(component, Property.class); 098 if (annotation != null) { 099 addProperty(annotation, defaultCategory); 100 } 101 return this; 102 } 103 104 private PropertyDefinitions addProperty(Property property, String defaultCategory) { 105 PropertyDefinition definition = PropertyDefinition.create(property); 106 return add(definition, defaultCategory); 107 } 108 109 private PropertyDefinitions add(PropertyDefinition definition, String defaultCategory) { 110 if (!definitions.containsKey(definition.key())) { 111 definitions.put(definition.key(), definition); 112 String category = StringUtils.defaultIfBlank(definition.category(), defaultCategory); 113 categories.put(definition.key(), new Category(category)); 114 String subcategory = StringUtils.defaultIfBlank(definition.subCategory(), category); 115 subcategories.put(definition.key(), new SubCategory(subcategory)); 116 if (!Strings.isNullOrEmpty(definition.deprecatedKey()) && !definition.deprecatedKey().equals(definition.key())) { 117 deprecatedKeys.put(definition.deprecatedKey(), definition.key()); 118 } 119 } 120 return this; 121 } 122 123 @CheckForNull 124 public PropertyDefinition get(String key) { 125 return definitions.get(validKey(key)); 126 } 127 128 public Collection<PropertyDefinition> getAll() { 129 return definitions.values(); 130 } 131 132 public String validKey(String key) { 133 return StringUtils.defaultString(deprecatedKeys.get(key), key); 134 } 135 136 /** 137 * @since 3.7 138 */ 139 public Map<Category, Map<SubCategory, Collection<PropertyDefinition>>> propertiesByCategory(@Nullable String qualifier) { 140 Map<Category, Map<SubCategory, Collection<PropertyDefinition>>> byCategory = new HashMap<>(); 141 if (qualifier == null) { 142 // Special categories on global page 143 Map<SubCategory, Collection<PropertyDefinition>> emailSubCategories = new HashMap<>(); 144 emailSubCategories.put(new SubCategory("email", true), new ArrayList<PropertyDefinition>()); 145 byCategory.put(new Category(CoreProperties.CATEGORY_GENERAL, false), emailSubCategories); 146 147 HashMap<SubCategory, Collection<PropertyDefinition>> licenseSubCategories = new HashMap<>(); 148 licenseSubCategories.put(new SubCategory("server_id", true), new ArrayList<PropertyDefinition>()); 149 byCategory.put(new Category(CoreProperties.CATEGORY_LICENSES, false), licenseSubCategories); 150 151 HashMap<SubCategory, Collection<PropertyDefinition>> encryptionSubCategories = new HashMap<>(); 152 encryptionSubCategories.put(new SubCategory("encryption", true), new ArrayList<PropertyDefinition>()); 153 byCategory.put(new Category(CoreProperties.CATEGORY_SECURITY, false), encryptionSubCategories); 154 } 155 for (PropertyDefinition definition : getAll()) { 156 if (qualifier == null ? definition.global() : definition.qualifiers().contains(qualifier)) { 157 Category category = categories.get(definition.key()); 158 if (!byCategory.containsKey(category)) { 159 byCategory.put(category, new HashMap<SubCategory, Collection<PropertyDefinition>>()); 160 } 161 SubCategory subCategory = subcategories.get(definition.key()); 162 if (!byCategory.get(category).containsKey(subCategory)) { 163 byCategory.get(category).put(subCategory, new ArrayList<PropertyDefinition>()); 164 } 165 byCategory.get(category).get(subCategory).add(definition); 166 } 167 } 168 return byCategory; 169 } 170 171 public String getDefaultValue(String key) { 172 PropertyDefinition def = get(key); 173 if (def == null) { 174 return null; 175 } 176 return StringUtils.defaultIfEmpty(def.defaultValue(), null); 177 } 178 179 public String getCategory(String key) { 180 return categories.get(validKey(key)).toString(); 181 } 182 183 public String getSubCategory(String key) { 184 return subcategories.get(validKey(key)).toString(); 185 } 186 187 public String getCategory(Property prop) { 188 return getCategory(prop.key()); 189 } 190 191 public String getNewKey(String deprecatedKey) { 192 return deprecatedKeys.get(deprecatedKey); 193 } 194 195 public String getDeprecatedKey(String key) { 196 PropertyDefinition def = get(key); 197 if (def == null) { 198 return null; 199 } 200 return StringUtils.defaultIfEmpty(def.deprecatedKey(), null); 201 } 202}