1 8 9 package test.javax.management.compliance.signature.support; 10 11 import java.io.Serializable ; 12 import java.lang.reflect.Field ; 13 import java.lang.reflect.Modifier ; 14 import java.util.ArrayList ; 15 import java.util.HashSet ; 16 import java.util.Iterator ; 17 import java.util.Set ; 18 19 22 public class SignatureVerifier 23 { 24 public void verifySignature(String className, ClassLoader jmxriLoader, ClassLoader mx4jLoader) throws Exception 25 { 26 Class jmxriClass = jmxriLoader.loadClass(className); 27 Class mx4jClass = mx4jLoader.loadClass(className); 28 29 int modifiers = jmxriClass.getModifiers(); 30 boolean isPublic = Modifier.isPublic(modifiers); 31 boolean isProtected = Modifier.isProtected(modifiers); 32 boolean isPackage = !Modifier.isPrivate(modifiers) && !isProtected && !isPublic; 33 boolean isSerializable = Serializable .class.isAssignableFrom(jmxriClass); 34 35 NotCompliantWarningException warning = null; 36 37 try 38 { 39 checkSameClassModifiers(jmxriClass, mx4jClass); 40 } 41 catch (NotCompliantWarningException x) 42 { 43 warning = x; 44 } 45 46 try 47 { 48 checkSameInheritance(jmxriClass, mx4jClass); 49 } 50 catch (NotCompliantWarningException x) 51 { 52 warning = x; 53 } 54 55 if (!isPackage) 56 { 57 try 58 { 59 checkSameConstructors(jmxriClass, mx4jClass); 60 } 61 catch (NotCompliantWarningException x) 62 { 63 warning = x; 64 } 65 try 66 { 67 checkSameMethods(jmxriClass, mx4jClass); 68 } 69 catch (NotCompliantWarningException x) 70 { 71 warning = x; 72 } 73 try 74 { 75 checkSameFields(jmxriClass, mx4jClass); 76 } 77 catch (NotCompliantWarningException x) 78 { 79 warning = x; 80 } 81 } 82 83 if (isSerializable) 84 { 85 try 86 { 87 checkSameSerialVersionUID(jmxriClass, mx4jClass); 88 } 89 catch (NotCompliantWarningException x) 90 { 91 warning = x; 92 } 93 } 94 95 if (warning != null) throw warning; 96 } 97 98 private void checkSameClassModifiers(Class jmxri, Class mx4j) throws NotCompliantException 99 { 100 int jmxriModifiers = jmxri.getModifiers(); 101 int mx4jModifers = mx4j.getModifiers(); 102 if (jmxriModifiers != mx4jModifers) 103 { 104 int modifier = jmxriModifiers ^ mx4jModifers; 105 if ((modifier & jmxriModifiers) != 0) 106 { 107 throw new NotCompliantException("JMX class " + jmxri.getName() + " in MX4J implementation is not declared " + Modifier.toString(modifier) + " as it should be"); 108 } 109 if ((modifier & mx4jModifers) != 0) 110 { 111 throw new NotCompliantWarningException("JMX class " + jmxri.getName() + " in MX4J implementation is declared " + Modifier.toString(modifier) + ", it is not in JMXRI"); 112 } 113 } 114 } 115 116 private void checkSameInheritance(Class jmxri, Class mx4j) throws NotCompliantException 117 { 118 120 Set jmxriInterfaces = new HashSet (); 121 Set mx4jInterfaces = new HashSet (); 122 for (Class jmxriParent = jmxri, mx4jParent = mx4j; jmxriParent != null; jmxriParent = jmxriParent.getSuperclass(), mx4jParent = mx4jParent.getSuperclass()) 123 { 124 findInterfaces(jmxriParent, jmxriInterfaces); 125 126 findInterfaces(mx4jParent, mx4jInterfaces); 127 128 if (!jmxriParent.getName().equals(mx4jParent.getName())) 129 { 130 throw new NotCompliantException("JMX class " + jmxri.getName() + " in MX4J implementation does not have the same hierarchy as JMXRI: " + mx4jParent.getName() + ", should be " + jmxriParent.getName()); 131 } 132 } 133 134 if (!jmxriInterfaces.containsAll(mx4jInterfaces)) 135 { 136 mx4jInterfaces.removeAll(jmxriInterfaces); 137 checkInterfacesHaveMethods(jmxri, mx4jInterfaces); 138 } 139 if (!mx4jInterfaces.containsAll(jmxriInterfaces)) 140 { 141 jmxriInterfaces.removeAll(mx4jInterfaces); 142 throw new NotCompliantException("JMX class " + jmxri.getName() + " in MX4J implementation does not implement the required interfaces: " + jmxriInterfaces); 143 } 144 } 145 146 private void findInterfaces(Class cls, Set interfaces) 147 { 148 Class [] intfs = cls.getInterfaces(); 149 for (int i = 0; i < intfs.length; ++i) 150 { 151 Class intf = intfs[i]; 152 boolean added = interfaces.add(intf.getName()); 153 if (added) findInterfaces(intf, interfaces); 154 } 155 } 156 157 private void checkInterfacesHaveMethods(Class cls, Set interfaces) throws NotCompliantException 158 { 159 boolean warning = false; 160 for (Iterator i = interfaces.iterator(); i.hasNext();) 161 { 162 String name = (String )i.next(); 163 if (name.equals("java.lang.Cloneable")) 164 warning = true; 165 else 166 warning = false; 167 } 168 169 if (warning) 170 throw new NotCompliantWarningException("JMX class " + cls.getName() + " in MX4J implementation implements too many tag interfaces: " + interfaces); 171 else 172 throw new NotCompliantException("JMX class " + cls.getName() + " in MX4J implementation implements too many interfaces: " + interfaces); 173 } 174 175 private void checkSameConstructors(final Class jmxri, Class mx4j) throws NotCompliantException 176 { 177 checkSameObjectMethod(new ObjectClass.Constructor(jmxri), new ObjectClass.Constructor(mx4j)); 178 } 179 180 private void checkSameMethods(Class jmxri, Class mx4j) throws NotCompliantException 181 { 182 checkSameObjectMethod(new ObjectClass.Method(jmxri), new ObjectClass.Method(mx4j)); 183 } 184 185 private void checkSameObjectMethod(ObjectClass jmxri, ObjectClass mx4j) throws NotCompliantException 186 { 187 Set jmxriMethods = wrapMethods(jmxri.getMethods()); 189 Set mx4jMethods = wrapMethods(mx4j.getMethods()); 190 checkSameMethods(jmxri.getName(), jmxriMethods, mx4jMethods); 191 192 jmxriMethods.clear(); 194 mx4jMethods.clear(); 195 for (ObjectClass jmxriParent = jmxri, mx4jParent = mx4j; jmxriParent != null; jmxriParent = jmxriParent.getSuperclass(), mx4jParent = mx4jParent.getSuperclass()) 196 { 197 ObjectMethod[] methods = jmxriParent.getDeclaredMethods(); 198 for (int i = 0; i < methods.length; ++i) 199 { 200 if (Modifier.isProtected(methods[i].getModifiers())) 201 { 202 jmxriMethods.add(wrapMethod(methods[i])); 203 } 204 } 205 206 methods = mx4jParent.getDeclaredMethods(); 207 for (int i = 0; i < methods.length; ++i) 208 { 209 if (Modifier.isProtected(methods[i].getModifiers())) 210 { 211 mx4jMethods.add(wrapMethod(methods[i])); 212 } 213 } 214 } 215 checkSameMethods(jmxri.getName(), jmxriMethods, mx4jMethods); 216 } 217 218 private void checkSameFields(Class jmxri, Class mx4j) throws NotCompliantException 219 { 220 Set jmxriFields = wrapFields(jmxri.getFields()); 222 Set mx4jFields = wrapFields(mx4j.getFields()); 223 checkSameFields(jmxri.getName(), jmxriFields, mx4jFields); 224 225 jmxriFields.clear(); 227 mx4jFields.clear(); 228 for (Class jmxriParent = jmxri, mx4jParent = mx4j; jmxriParent != null; jmxriParent = jmxriParent.getSuperclass(), mx4jParent = mx4jParent.getSuperclass()) 229 { 230 Field [] fields = jmxriParent.getDeclaredFields(); 231 for (int i = 0; i < fields.length; ++i) 232 { 233 if (Modifier.isProtected(fields[i].getModifiers())) 234 { 235 jmxriFields.add(wrapField(fields[i])); 236 } 237 } 238 239 fields = mx4jParent.getDeclaredFields(); 240 for (int i = 0; i < fields.length; ++i) 241 { 242 if (Modifier.isProtected(fields[i].getModifiers())) 243 { 244 mx4jFields.add(wrapField(fields[i])); 245 } 246 } 247 } 248 checkSameFields(jmxri.getName(), jmxriFields, mx4jFields); 249 } 250 251 private void checkSameSerialVersionUID(Class jmxriClass, Class mx4jClass) throws NotCompliantException 252 { 253 try 254 { 255 Field jmxriField = jmxriClass.getField("serialVersionUID"); 256 jmxriField.setAccessible(true); 257 Field mx4jField = mx4jClass.getField("serialVersionUID"); 258 mx4jField.setAccessible(true); 259 long jmxriValue = jmxriField.getLong(null); 260 long mx4jValue = jmxriField.getLong(null); 261 if (jmxriValue != mx4jValue) throw new NotCompliantException("JMX class " + jmxriClass.getName() + " in MX4J implementation does not have the same serialVersionUID: expecting " + jmxriValue + ", found " + mx4jValue); 262 } 263 catch (NoSuchFieldException ignored) 264 { 265 } 267 catch (NotCompliantException x) 268 { 269 throw x; 270 } 271 catch (Exception x) 272 { 273 x.printStackTrace(); 274 throw new NotCompliantException("Unknown problems in checking serialVersionUID: " + x); 275 } 276 } 277 278 private Set wrapMethods(ObjectMethod[] methods) 279 { 280 Set set = new HashSet (); 281 for (int i = 0; i < methods.length; ++i) 282 { 283 set.add(wrapMethod(methods[i])); 284 } 285 return set; 286 } 287 288 private MethodWrapper wrapMethod(ObjectMethod method) 289 { 290 return new MethodWrapper(method); 291 } 292 293 private Set wrapFields(Field [] fields) 294 { 295 HashSet set = new HashSet (); 296 for (int i = 0; i < fields.length; ++i) 297 { 298 set.add(wrapField(fields[i])); 299 } 300 return set; 301 } 302 303 private FieldWrapper wrapField(Field field) 304 { 305 return new FieldWrapper(field); 306 } 307 308 private void checkSameMethods(String name, Set jmxri, Set mx4j) throws NotCompliantException 309 { 310 if (!jmxri.containsAll(mx4j)) 311 { 312 checkDifferentMethods(name, mx4j, jmxri); 313 } 314 315 if (!mx4j.containsAll(jmxri)) 316 { 317 checkDifferentMethods(name, jmxri, mx4j); 318 } 319 } 320 321 private void checkDifferentMethods(String name, Set set1, Set set2) throws NotCompliantException 322 { 323 set1.removeAll(set2); 324 325 boolean warning = false; 326 boolean error = false; 327 ArrayList warnings = new ArrayList (); 328 ArrayList errors = new ArrayList (); 329 for (Iterator i = set1.iterator(); i.hasNext();) 330 { 331 MethodWrapper method1 = (MethodWrapper)i.next(); 332 boolean found = false; 333 for (Iterator j = set2.iterator(); j.hasNext();) 334 { 335 MethodWrapper method2 = (MethodWrapper)j.next(); 336 if (method1.isSameMethod(method2)) 337 { 338 if (!method1.sameSignatureModifiers(method2)) 339 { 340 warning = true; 341 warnings.add(method1); 342 warnings.add(method2); 343 } 344 else 345 { 346 if (method1.throwsClauseDifferForRuntimeExceptionsOnly(method2)) 347 { 348 warning = true; 349 warnings.add(method1); 350 warnings.add(method2); 351 } 352 else 353 { 354 error = true; 355 errors.add(method1); 356 errors.add(method2); 357 } 358 } 359 found = true; 360 break; 361 } 362 } 363 if (!found) throw new NotCompliantException("JMX class " + name + " in MX4J implementation has different interface: " + set1); 364 } 365 366 if (error) throw new NotCompliantException("JMX class " + name + " in MX4J implementation has different signature: " + errors); 367 if (warning) throw new NotCompliantWarningException("JMX class " + name + " in MX4J implementation has different signature: " + warnings); 368 throw new IllegalStateException (); 369 } 370 371 private void checkSameFields(String name, Set jmxri, Set mx4j) throws NotCompliantException 372 { 373 if (!jmxri.containsAll(mx4j)) 374 { 375 mx4j.removeAll(jmxri); 376 throw new NotCompliantException("JMX class " + name + " in MX4J implementation has too many fields: " + mx4j); 377 } 378 if (!mx4j.containsAll(jmxri)) 379 { 380 jmxri.removeAll(mx4j); 381 throw new NotCompliantException("JMX class " + name + " in MX4J implementation does not have the required fields: " + jmxri); 382 } 383 } 384 } 385 | Popular Tags |