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