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 }