/* * Copyright 2005-2010 Ignis Software Tools Ltd. All rights reserved. */ package jsystem.runner.projectsync; import java.io.File; import java.math.BigInteger; import java.security.MessageDigest; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Vector; import jsystem.framework.scenario.JTest; import jsystem.framework.scenario.RunnerTest; import jsystem.framework.scenario.Scenario; import jsystem.framework.scenario.ScenariosManager; import jsystem.runner.agent.ProjectComponent; import jsystem.utils.FileUtils; /** * Service class which performs automation project MD5 calculations.<br> * For more information please reas {@link } * @author goland */ public class MD5Calculator { private File projectClassesPath; /** * Constructs a {@link MD5Calculator} * @param testsClassesPath full path to tests classes folder. */ public MD5Calculator(File testsClassesPath) throws Exception{ this.projectClassesPath = testsClassesPath; } /** * Calculates classes md5.<br> * the md5 of all packages under tests classes folder is calculates * besides sut package folder and scenarios package folder. */ public String calculateClassesMD5() throws Exception { File[] subFolders = projectClassesPath.listFiles(); MessageDigest md = MessageDigest.getInstance("MD5"); for (File file:subFolders){ if (file.getName().equals("sut")){ continue; } if (file.getName().equals("scenarios")){ continue; } FileUtils.updateMessageDigest(file, md); } byte[] hash = md.digest(); BigInteger result = new BigInteger(hash); String rc = result.toString(16); return rc; } /** * Calculates automation project scenarios package folder md5. */ public String calculateScenariosMD5() throws Exception { File scenariosPath = new File(projectClassesPath,"scenarios"); if (!scenariosPath.exists()){ return ""; } return FileUtils.getMD5(scenariosPath); } /** * Calculates automation project sut package folder md5. */ public String calculateSUTMD5() throws Exception { File sutPath = new File(projectClassesPath,"sut"); if (!sutPath.exists()){ return ""; } return FileUtils.getMD5(sutPath); } /** * Calculates automation project lib folder md5. */ public String calculateLibsMD5() throws Exception { File libsPath = new File(projectClassesPath.getParent(),"lib"); if (!libsPath.exists()){ return ""; } return FileUtils.getMD5(libsPath); } /** * Calculates automation project resources folder md5. */ public String calculateResourcesMD5() throws Exception { File resourcesPath = new File(projectClassesPath.getParent(),"resources"); if (!resourcesPath.exists()){ return ""; } return FileUtils.getMD5(resourcesPath); } /** * Returns a map with project components md5.<br> * @param components - automation project components for which md5 is calculate. */ public Map<ProjectComponent, String> getProjectMD5(ProjectComponent[] components) throws Exception { HashMap<ProjectComponent,String> map = new HashMap<ProjectComponent, String>(); for (ProjectComponent component:components){ String value = ""; if (component.equals(ProjectComponent.classes)){ value = calculateClassesMD5(); }else if (component.equals(ProjectComponent.libs)){ value = calculateLibsMD5(); }else if (component.equals(ProjectComponent.suts)){ value = calculateSUTMD5(); }else if (component.equals(ProjectComponent.scenarios)){ value = calculateScenariosMD5(); }else if (component.equals(ProjectComponent.resources)){ value = calculateResourcesMD5(); } map.put(component,value); } return map; } /** * Returns whole project digest with special treatment to current scenario.<br> * @see #calculateScenarioMD5 */ public String calculateProjectMD5(String scenarioName) throws Exception { Scenario s = ScenariosManager.getInstance().getScenario(scenarioName); s.loadParametersAndValues(); String scenarioMD5 = calculateScenarioMD5(s); Map<ProjectComponent,String> map = getProjectMD5(new ProjectComponent[]{ProjectComponent.resources,ProjectComponent.classes,ProjectComponent.suts,ProjectComponent.libs}); map.put(ProjectComponent.currentScenario,scenarioMD5); MessageDigest md = MessageDigest.getInstance("MD5"); Iterator<String> iter = map.values().iterator(); while (iter.hasNext()){ md.update(iter.next().getBytes()); } byte[] hash = md.digest(); BigInteger result = new BigInteger(hash); String rc = result.toString(16); return rc; } /** * Calculates scenario MD5.<br> * The method was added to support special treatment to current scenario: * When calculating project MD5, I want to ignore tests selections.<br> * Regular file MD5 calculation will calculate also selection, so to workaround * it, I load the scenario and calculate the MD5 of each test, and ignore selection. * * TODO method is not operational yet. */ private static String calculateScenarioMD5(Scenario scenario) throws Exception { MessageDigest md = MessageDigest.getInstance("MD5"); Vector<JTest> allTests = scenario.getTests(); for (JTest t:allTests){ String name = t.getTestName()+t.getTestId(); String parameters = ""; if (t instanceof RunnerTest){ parameters = ((RunnerTest)t).getPropertiesAsString(); } md.update(name.getBytes()); md.update(parameters.getBytes()); } byte[] hash = md.digest(); BigInteger result = new BigInteger(hash); String rc = result.toString(16); return rc; } /** * Compares the md5 of two projects and returns and array of the components * which are different between two projects. */ public static ProjectComponent[] diffProjectsMd5(Map<ProjectComponent,String> project1,Map<ProjectComponent,String> project2){ HashSet<ProjectComponent> set = new HashSet<ProjectComponent>(); Iterator<ProjectComponent> proj1Iter = project1.keySet().iterator(); while (proj1Iter.hasNext()){ ProjectComponent componentString = proj1Iter.next(); String proj1Val = project1.get(componentString); String proj2Val = project2.get(componentString); if (!proj1Val.equals(proj2Val)){ set.add(componentString); } } Iterator<ProjectComponent> proj2Iter = project2.keySet().iterator(); while (proj2Iter.hasNext()){ ProjectComponent componentString = proj2Iter.next(); String proj1Val = project1.get(componentString); String proj2Val = project2.get(componentString); if (!proj2Val.equals(proj1Val)){ set.add(componentString); } } return set.toArray(new ProjectComponent[0]); } }