/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/proctor/resource/legal-notices/Proctor.LICENSE * or https://proctor.dev.java.net/Proctor.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2009 Sun Microsystems, Inc. */ package com.ibm.staf.service.opends.tester; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; import javax.xml.bind.JAXBElement; import java.util.Collection; import java.util.Collections; import org.opends.dsml.protocol.DsmlAttr; import org.opends.server.core.DirectoryServer; import org.opends.server.types.DN; import org.opends.server.types.DirectoryException; public class Checker { private static final String JAXB_GENERATED_PACKAGE_NAME = "org.opends.dsml.protocol"; // Key=JAXB classes, Value=List of methods to get attribute private static final Map<Class, List<Method>> CACHE = new HashMap<Class, List<Method>>(); // Helpfull to keep track of what argument is currently processed private static final Stack<Method> STACK = new Stack<Method>(); // A list of attribute that are prevented to be checked private static final Set<String> DO_NOT_CHECK = new HashSet<String>(); static { DO_NOT_CHECK.add("ResultCode.getDescr"); // ResultCode.getCode is enough DO_NOT_CHECK.add("LDAPResult.getErrorMessage"); // LDAPResult.getResultCode is enough DO_NOT_CHECK.add("ErrorResponse.getMessage"); } private static DsmlAttrCompare dsmlAttrCompare = new DsmlAttrCompare(); static { // needed otherwise the SearchResultEntry like in test moddn998.res fail // in the equals() method on DN.decode((String) o1.... DirectoryServer.bootstrapClient(); } private static List<Method> getAttributes(Class clazz) { List<Method> result = CACHE.get(clazz); if (result == null) { result = new ArrayList<Method>(); for (Method method : clazz.getMethods()) { String methodName = method.getName(); Class returnType = method.getReturnType(); if (!method.getDeclaringClass().getName().startsWith(JAXB_GENERATED_PACKAGE_NAME)) { continue; } if (((methodName.startsWith("get") && (methodName.length() > 3) && (!returnType.equals(void.class))) || (methodName.startsWith("is") && (methodName.length() > 2) && (returnType.equals(boolean.class)))) && (method.getParameterTypes().length == 0)) { result.add(method); } } CACHE.put(clazz, result); } return result; } private static String buildMessage() { // return ""; StringBuilder sb = new StringBuilder(STACK.peek().toGenericString()).append(" in JAXB "); int size = STACK.size(); for (int i = 0; i < size; i++) { sb.append(i == 0 ? "" : ".").append(STACK.get(i).getName()).append("()"); } return sb.toString(); } public static boolean equals(Object o1, Object o2) { if (o1 == null && o2 == null) { return true; } if (o1 == null || o2 == null) { throw new JAXBCheckerException("One of the two is null : " + buildMessage()); } // both are not null Class c1 = o1.getClass(); if (!o2.getClass().equals(c1)) { throw new JAXBCheckerException("Type mismatch (" + c1.getName() + " vs " + o2.getClass().getName() + ") : " + buildMessage()); } if (c1.getName().startsWith(JAXB_GENERATED_PACKAGE_NAME)) { for (Method method : getAttributes(c1)) { String fullName = method.getDeclaringClass().getName() + "." + method.getName(); String s = fullName.substring(JAXB_GENERATED_PACKAGE_NAME.length() + 1, fullName.length()); if (DO_NOT_CHECK.contains(s)) { continue; } Object r1, r2; try { STACK.push(method); r1 = method.invoke(o1); r2 = method.invoke(o2); if (!equals(r1, r2)) { // if false an exception will be thown STACK.pop(); return false; } STACK.pop(); } catch (Exception e) { throw (RuntimeException) e; } } } else if (o1 instanceof List) { // Transering into sets whenever ordering is required Collection l1; Collection l2; l1 = (List) o1; l2 = (List) o2; if (l1 != null && l1.size() > 1 && l1.toArray()[0] instanceof DsmlAttr) { Collections.sort((List) l1, dsmlAttrCompare); Collections.sort((List) l2, dsmlAttrCompare); } else if (l1 != null && l1.size() > 1 && l1.toArray()[0] instanceof String) { Collections.sort((List) l1); Collections.sort((List) l2); } /* if (((List) o2).size() != l2.size()) { for (Object o : l2) { System.out.println("collection2 : " + o); } for (Object o : (List) o2) { System.out.println("list2 : " + o); } throw (new RuntimeException("object2 size changed")); } */ if (l1.size() != l2.size()) { for (Object o : l1) { System.out.println("list1 : " + o); } for (Object o : l2) { System.out.println("list2 : " + o); } throw new JAXBCheckerException("List size mismatch (received=" + l1.size() + ", expected=" + l2.size() + "): " + buildMessage()); } for (int i = 0; i < l1.size(); i++) { // could be optimized :( if (!equals(l1.toArray()[i], l2.toArray()[i])) { // if false an exception will be thown return false; } } } else if (o1 instanceof JAXBElement) { return equals(((JAXBElement) o1).getValue(), ((JAXBElement) o2).getValue()); } else if (o1 instanceof String) { // special case in case a DN must be checked // This is not a full check for DN but DN.decode(String) needs a DS to run if (STACK.size() > 0) { String s = STACK.peek().getName(); if (s.equalsIgnoreCase("getDn") || s.equalsIgnoreCase("getMatchedDN")) { try { if (!DN.decode((String) o1).equals(DN.decode((String) o2))) { throw new JAXBCheckerException("DN mismatch : " + o1 + " vs " + o2 + " " + buildMessage()); } } catch (DirectoryException ex) { throw new JAXBCheckerException("DN mismatch : " + o1 + " vs " + o2 + " " + buildMessage()); } // String oo1 = ((String) o1).replace(" ", ""); // String oo2 = ((String) o2).replace(" ", ""); // if (!oo1.equalsIgnoreCase(oo2)) { // throw new JAXBCheckerException("DN mismatch : " + o1 + " vs " + o2 + " " + buildMessage()); // } } else if (s.equalsIgnoreCase("getName")) { if (!((String) o1).equalsIgnoreCase((String) o2)) { throw new JAXBCheckerException("Attribute mismatch : " + o1 + " vs " + o2 + " " + buildMessage()); } } else { if (!o1.equals(o2)) { throw new JAXBCheckerException("String mismatch : " + o1 + " vs " + o2 + " " + buildMessage()); } } } } else { if (!o1.equals(o2)) { if (STACK.size() > 0) { String s = STACK.peek().getName(); if (s.equalsIgnoreCase("getCode")) { throw new JAXBCheckerException("Error code mismatch : " + LDAPResultCode.toString((Integer) o1) + "[" + o1 + "] vs " + LDAPResultCode.toString((Integer) o2) + "[" + o2 + "]" + buildMessage()); } else { throw new JAXBCheckerException("Object mismatch : [class = " + o1.getClass().getSimpleName() + "]" + buildMessage()); } } } } return true; } }