View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd;
5   
6   import java.util.ArrayList;
7   import java.util.Collections;
8   import java.util.HashMap;
9   import java.util.Iterator;
10  import java.util.List;
11  import java.util.Map;
12  import java.util.Set;
13  
14  import net.sourceforge.pmd.util.CollectionUtil;
15  
16  /**
17   * Base class for objects which can be configured through properties. Rules and
18   * Reports are such objects.
19   * 
20   * @author Brian Remedios
21   */
22  public abstract class AbstractPropertySource implements PropertySource {
23  
24      /** The list of known properties that can be configured. */
25      protected List<PropertyDescriptor<?>> propertyDescriptors = new ArrayList<>();
26      /** The values for each property. */
27      protected Map<PropertyDescriptor<?>, Object> propertyValuesByDescriptor = new HashMap<>();
28  
29      /**
30       * Creates a copied list of the property descriptors and returns it.
31       * 
32       * @return a copy of the property descriptors.
33       */
34      protected List<PropertyDescriptor<?>> copyPropertyDescriptors() {
35          List<PropertyDescriptor<?>> copy = new ArrayList<>(propertyDescriptors.size());
36          copy.addAll(propertyDescriptors);
37          return copy;
38      }
39  
40      /**
41       * Creates a copied map of the values of the properties and returns it.
42       * 
43       * @return a copy of the values
44       */
45      protected Map<PropertyDescriptor<?>, Object> copyPropertyValues() {
46          Map<PropertyDescriptor<?>, Object> copy = new HashMap<>(
47                  propertyValuesByDescriptor.size());
48          copy.putAll(propertyValuesByDescriptor);
49          return copy;
50      }
51  
52      /**
53       * {@inheritDoc}
54       */
55      public Set<PropertyDescriptor<?>> ignoredProperties() {
56          return Collections.emptySet();
57      }
58  
59      /**
60       * {@inheritDoc}
61       */
62      public void definePropertyDescriptor(PropertyDescriptor<?> propertyDescriptor) {
63          // Check to ensure the property does not already exist.
64          for (PropertyDescriptor<?> descriptor : propertyDescriptors) {
65              if (descriptor.name().equals(propertyDescriptor.name())) {
66                  throw new IllegalArgumentException("There is already a PropertyDescriptor with name '"
67                          + propertyDescriptor.name() + "' defined on Rule " + getName() + ".");
68              }
69          }
70          propertyDescriptors.add(propertyDescriptor);
71          // Sort in UI order
72          Collections.sort(propertyDescriptors);
73      }
74  
75      /**
76       * Gets the name of the property source. This is e.g. the rule name or the report name.
77       * @return the name
78       */
79      public abstract String getName();
80  
81      /**
82       * {@inheritDoc}
83       */
84      @Override
85      public PropertyDescriptor<?> getPropertyDescriptor(String name) {
86          for (PropertyDescriptor<?> propertyDescriptor : propertyDescriptors) {
87              if (name.equals(propertyDescriptor.name())) {
88                  return propertyDescriptor;
89              }
90          }
91          return null;
92      }
93  
94      /**
95       * {@inheritDoc}
96       */
97      @Override
98      public boolean hasDescriptor(PropertyDescriptor<?> descriptor) {
99  
100         if (propertyValuesByDescriptor.isEmpty()) {
101             propertyValuesByDescriptor = getPropertiesByPropertyDescriptor();
102         }
103 
104         return propertyValuesByDescriptor.containsKey(descriptor);
105     }
106 
107     /**
108      * {@inheritDoc}
109      */
110     @Override
111     public List<PropertyDescriptor<?>> getPropertyDescriptors() {
112         return propertyDescriptors;
113     }
114 
115     /**
116      * {@inheritDoc}
117      */
118     @Override
119     public <T> T getProperty(PropertyDescriptor<T> propertyDescriptor) {
120         checkValidPropertyDescriptor(propertyDescriptor);
121         T result = propertyDescriptor.defaultValue();
122         if (propertyValuesByDescriptor.containsKey(propertyDescriptor)) {
123             @SuppressWarnings("unchecked")
124             T value = (T) propertyValuesByDescriptor.get(propertyDescriptor);
125             result = value;
126         }
127         return result;
128     }
129 
130     /**
131      * {@inheritDoc}
132      */
133     @Override
134     public <T> void setProperty(PropertyDescriptor<T> propertyDescriptor, T value) {
135         checkValidPropertyDescriptor(propertyDescriptor);
136         propertyValuesByDescriptor.put(propertyDescriptor, value);
137     }
138 
139     private void checkValidPropertyDescriptor(PropertyDescriptor<?> propertyDescriptor) {
140         if (!propertyDescriptors.contains(propertyDescriptor)) {
141             throw new IllegalArgumentException("Property descriptor not defined for Rule " + getName() + ": "
142                     + propertyDescriptor);
143         }
144     }
145 
146     /**
147      * {@inheritDoc}
148      */
149     @Override
150     public Map<PropertyDescriptor<?>, Object> getPropertiesByPropertyDescriptor() {
151         if (propertyDescriptors.isEmpty()) {
152             return Collections.emptyMap();
153         }
154 
155         Map<PropertyDescriptor<?>, Object> propertiesByPropertyDescriptor = new HashMap<>(
156                 propertyDescriptors.size());
157         // Fill with existing explicitly values
158         propertiesByPropertyDescriptor.putAll(this.propertyValuesByDescriptor);
159 
160         // Add default values for anything not yet set
161         for (PropertyDescriptor<?> propertyDescriptor : this.propertyDescriptors) {
162             if (!propertiesByPropertyDescriptor.containsKey(propertyDescriptor)) {
163                 propertiesByPropertyDescriptor.put(propertyDescriptor, propertyDescriptor.defaultValue());
164             }
165         }
166 
167         return propertiesByPropertyDescriptor;
168     }
169 
170     /**
171      * {@inheritDoc}
172      */
173     @Override
174     public boolean usesDefaultValues() {
175 
176         Map<PropertyDescriptor<?>, Object> valuesByProperty = getPropertiesByPropertyDescriptor();
177         if (valuesByProperty.isEmpty()) {
178             return true;
179         }
180 
181         Iterator<Map.Entry<PropertyDescriptor<?>, Object>> iter = valuesByProperty.entrySet().iterator();
182 
183         while (iter.hasNext()) {
184             Map.Entry<PropertyDescriptor<?>, Object> entry = iter.next();
185             if (!CollectionUtil.areEqual(entry.getKey().defaultValue(), entry.getValue())) {
186                 return false;
187             }
188         }
189 
190         return true;
191     }
192 
193     /**
194      * {@inheritDoc}
195      */
196     @Override
197     public void useDefaultValueFor(PropertyDescriptor<?> desc) {
198         propertyValuesByDescriptor.remove(desc);
199     }
200 
201     /**
202      * {@inheritDoc}
203      */
204     @Override
205     public String dysfunctionReason() {
206         return null;
207     }
208 }