View Javadoc

    1   package net.sourceforge.pmd.lang.rule.properties;
    2
    3   import java.util.HashSet;
    4   import java.util.Map;
    5   import java.util.Set;
    6
    7   import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory;
    8   import static net.sourceforge.pmd.PropertyDescriptorFields.*;
    9
    10  /**
    11   * Concrete subclasses manage items that reside within namespaces per the design of the Java language.
    12   * Rule developers can limit the range of permissible items by specifying portions of their package
    13   * names in the constructor. If the legalPackageNames value is set to null then no restrictions are
    14   * made.
    15   *
    16   * @author Brian Remedios
    17   * @param <T>
    18   */
    19  public abstract class AbstractPackagedProperty<T> extends AbstractProperty<T> {
    20
    21  	private String[] legalPackageNames;
    22
    23  	private static final char PACKAGE_NAME_DELIMITER = ' ';
    24
    25  	protected static final Map<String, Boolean> packagedFieldTypesByKey = BasicPropertyDescriptorFactory.expectedFieldTypesWith(
    26  			new String[]  { LEGAL_PACKAGES},
    27  			new Boolean[] { Boolean.FALSE}
    28  			);
    29
    30
    31      protected static String[] packageNamesIn(Map<String, String> params) {
    32          // TODO
    33          return null;
    34      }
    35
    36  	/**
    37  	 *
    38  	 * @param theName
    39  	 * @param theDescription
    40  	 * @param theDefault
    41  	 * @param theLegalPackageNames
    42  	 * @param theUIOrder
    43  	 * @throws IllegalArgumentException
    44  	 */
    45  	protected AbstractPackagedProperty(String theName, String theDescription, T theDefault, String[] theLegalPackageNames, float theUIOrder) {
    46  		super(theName, theDescription, theDefault, theUIOrder);
    47
    48  		checkValidPackages(theDefault, theLegalPackageNames);
    49
    50  		legalPackageNames = theLegalPackageNames;
    51  	}
    52
    53      /**
    54       * @param attributes Map<String,String>
    55       */
    56      protected void addAttributesTo(Map<String, String> attributes) {
    57          super.addAttributesTo(attributes);
    58
    59          attributes.put(LEGAL_PACKAGES, delimitedPackageNames());
    60      }
    61
    62      /**
    63       * @return String
    64       */
    65      private final String delimitedPackageNames() {
    66
    67          if (legalPackageNames == null || legalPackageNames.length == 0) { return ""; }
    68          if (legalPackageNames.length == 1) { return legalPackageNames[0];  }
    69
    70          StringBuilder sb = new StringBuilder();
    71          sb.append(legalPackageNames[0]);
    72          for (int i=1; i<legalPackageNames.length; i++) {
    73              sb.append(PACKAGE_NAME_DELIMITER).append(legalPackageNames[i]);
    74          }
    75          return sb.toString();
    76      }
    77
    78  	/**
    79  	 * Evaluates the names of the items against the allowable name prefixes. If one or more
    80  	 * do not have valid prefixes then an exception will be thrown.
    81  	 *
    82  	 * @param item
    83  	 * @param legalNamePrefixes
    84  	 * @throws IllegalArgumentException
    85  	 */
    86  	private void checkValidPackages(Object item, String[] legalNamePrefixes) {
    87  	    Object[] items;
    88  	    if (item.getClass().isArray()) {
    89  		items = (Object[])item;
    90  	    } else{
    91  		items = new Object[]{item};
    92  	    }
    93
    94  		String[] names = new String[items.length];
    95  		Set<String> nameSet = new HashSet<String>(items.length);
    96  		String name = null;
    97
    98  		for (int i=0; i<items.length; i++) {
    99  			name = packageNameOf(items[i]);
    100 			names[i] = name;
    101 			nameSet.add(name);
    102 		}
    103
    104 		for (int i=0; i<names.length; i++) {
    105 			for (int l=0; l<legalNamePrefixes.length; l++) {
    106 				if (names[i].startsWith(legalNamePrefixes[l])) {
    107 					nameSet.remove(names[i]);
    108 					break;
    109 				}
    110 			}
    111 		}
    112 		if (nameSet.isEmpty()) { return; }
    113
    114 		throw new IllegalArgumentException("Invalid items: " + nameSet);
    115 	}
    116
    117 	/**
    118 	 * Method itemTypeName.
    119 	 * @return String
    120 	 */
    121 	abstract protected String itemTypeName();
    122
    123 	/**
    124 	 *
    125 	 * @param value Object
    126 	 * @return String
    127 	 */
    128 	protected String valueErrorFor(Object value) {
    129
    130 		if (value == null) {
    131 			String err = super.valueErrorFor(null);
    132 			if (err != null) { return err; }
    133 			}
    134
    135 		if (legalPackageNames == null) {
    136 			return null;	// no restriction
    137 		}
    138
    139 		String name = packageNameOf(value);
    140
    141 		for (int i=0; i<legalPackageNames.length; i++) {
    142 			if (name.startsWith(legalPackageNames[i])) {
    143 				return null;
    144 			}
    145 		}
    146
    147 		return "Disallowed " + itemTypeName() + ": " + name;
    148 	}
    149
    150 	/**
    151 	 *
    152 	 * @param item Object
    153 	 * @return String
    154 	 */
    155 	abstract protected String packageNameOf(Object item);
    156
    157 	/**
    158 	 *
    159 	 * @return String[]
    160 	 */
    161 	public String[] legalPackageNames() {
    162 		return legalPackageNames;
    163 	}
    164
    165 }