/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sourceforge.pmd.util.CollectionUtil;
/**
* Base class for objects which can be configured through properties. Rules and
* Reports are such objects.
*
* @author Brian Remedios
*/
public abstract class AbstractPropertySource implements PropertySource {
/** The list of known properties that can be configured. */
protected List<PropertyDescriptor<?>> propertyDescriptors = new ArrayList<>();
/** The values for each property. */
protected Map<PropertyDescriptor<?>, Object> propertyValuesByDescriptor = new HashMap<>();
/**
* Creates a copied list of the property descriptors and returns it.
*
* @return a copy of the property descriptors.
*/
protected List<PropertyDescriptor<?>> copyPropertyDescriptors() {
return new ArrayList<>(propertyDescriptors);
}
/**
* Creates a copied map of the values of the properties and returns it.
*
* @return a copy of the values
*/
protected Map<PropertyDescriptor<?>, Object> copyPropertyValues() {
return new HashMap<>(propertyValuesByDescriptor);
}
/**
* {@inheritDoc}
*/
@Override
public Set<PropertyDescriptor<?>> ignoredProperties() {
return Collections.emptySet();
}
/**
* {@inheritDoc}
*/
@Override
public void definePropertyDescriptor(PropertyDescriptor<?> propertyDescriptor) {
// Check to ensure the property does not already exist.
for (PropertyDescriptor<?> descriptor : propertyDescriptors) {
if (descriptor.name().equals(propertyDescriptor.name())) {
throw new IllegalArgumentException("There is already a PropertyDescriptor with name '"
+ propertyDescriptor.name() + "' defined on Rule " + getName() + ".");
}
}
propertyDescriptors.add(propertyDescriptor);
// Sort in UI order
Collections.sort(propertyDescriptors);
}
/**
* Gets the name of the property source. This is e.g. the rule name or the
* report name.
*
* @return the name
*/
public abstract String getName();
/**
* {@inheritDoc}
*/
@Override
public PropertyDescriptor<?> getPropertyDescriptor(String name) {
for (PropertyDescriptor<?> propertyDescriptor : propertyDescriptors) {
if (name.equals(propertyDescriptor.name())) {
return propertyDescriptor;
}
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasDescriptor(PropertyDescriptor<?> descriptor) {
if (propertyValuesByDescriptor.isEmpty()) {
propertyValuesByDescriptor = getPropertiesByPropertyDescriptor();
}
return propertyValuesByDescriptor.containsKey(descriptor);
}
/**
* {@inheritDoc}
*/
@Override
public List<PropertyDescriptor<?>> getPropertyDescriptors() {
return propertyDescriptors;
}
/**
* {@inheritDoc}
*/
@Override
public <T> T getProperty(PropertyDescriptor<T> propertyDescriptor) {
checkValidPropertyDescriptor(propertyDescriptor);
T result = propertyDescriptor.defaultValue();
if (propertyValuesByDescriptor.containsKey(propertyDescriptor)) {
@SuppressWarnings("unchecked")
T value = (T) propertyValuesByDescriptor.get(propertyDescriptor);
result = value;
}
return result;
}
/**
* {@inheritDoc}
*/
@Override
public <T> void setProperty(PropertyDescriptor<T> propertyDescriptor, T value) {
checkValidPropertyDescriptor(propertyDescriptor);
propertyValuesByDescriptor.put(propertyDescriptor, value);
}
private void checkValidPropertyDescriptor(PropertyDescriptor<?> propertyDescriptor) {
if (!propertyDescriptors.contains(propertyDescriptor)) {
throw new IllegalArgumentException(
"Property descriptor not defined for Rule " + getName() + ": " + propertyDescriptor);
}
}
/**
* {@inheritDoc}
*/
@Override
public Map<PropertyDescriptor<?>, Object> getPropertiesByPropertyDescriptor() {
if (propertyDescriptors.isEmpty()) {
return Collections.emptyMap();
}
Map<PropertyDescriptor<?>, Object> propertiesByPropertyDescriptor = new HashMap<>(propertyDescriptors.size());
// Fill with existing explicitly values
propertiesByPropertyDescriptor.putAll(this.propertyValuesByDescriptor);
// Add default values for anything not yet set
for (PropertyDescriptor<?> propertyDescriptor : this.propertyDescriptors) {
if (!propertiesByPropertyDescriptor.containsKey(propertyDescriptor)) {
propertiesByPropertyDescriptor.put(propertyDescriptor, propertyDescriptor.defaultValue());
}
}
return propertiesByPropertyDescriptor;
}
/**
* {@inheritDoc}
*/
@Override
public boolean usesDefaultValues() {
Map<PropertyDescriptor<?>, Object> valuesByProperty = getPropertiesByPropertyDescriptor();
if (valuesByProperty.isEmpty()) {
return true;
}
Iterator<Map.Entry<PropertyDescriptor<?>, Object>> iter = valuesByProperty.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<PropertyDescriptor<?>, Object> entry = iter.next();
if (!CollectionUtil.areEqual(entry.getKey().defaultValue(), entry.getValue())) {
return false;
}
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public void useDefaultValueFor(PropertyDescriptor<?> desc) {
propertyValuesByDescriptor.remove(desc);
}
/**
* {@inheritDoc}
*/
@Override
public String dysfunctionReason() {
return null;
}
}