Java tutorial
/* * ProActive Parallel Suite(TM): * The Open Source library for parallel and distributed * Workflows & Scheduling, Orchestration, Cloud Automation * and Big Data Analysis on Enterprise Grids & Clouds. * * Copyright (c) 2007 - 2017 ActiveEon * Contact: contact@activeeon.com * * This library is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License * as published by the Free Software Foundation: version 3 of * the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * If needed, contact us to obtain a release under GPL Version 2 or 3 * or a different license than the AGPL. */ package org.ow2.proactive.scheduler.common.job.factories; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; 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 org.apache.commons.collections4.CollectionUtils; import org.ow2.proactive.scheduler.common.job.TaskFlowJob; import org.ow2.proactive.scheduler.common.task.CommonAttribute; import org.ow2.proactive.scheduler.common.task.ForkEnvironment; import org.ow2.proactive.scheduler.common.task.JavaTask; import org.ow2.proactive.scheduler.common.task.NativeTask; import org.ow2.proactive.scheduler.common.task.ParallelEnvironment; import org.ow2.proactive.scheduler.common.task.ScriptTask; import org.ow2.proactive.scheduler.common.task.Task; import org.ow2.proactive.scheduler.common.task.UpdatableProperties; import org.ow2.proactive.scheduler.common.task.dataspaces.InputSelector; import org.ow2.proactive.scheduler.common.task.dataspaces.OutputSelector; import org.ow2.proactive.scheduler.common.task.flow.FlowScript; import org.ow2.proactive.scripting.Script; import org.ow2.proactive.scripting.SelectionScript; import org.ow2.proactive.topology.descriptor.ThresholdProximityDescriptor; import org.ow2.proactive.topology.descriptor.TopologyDescriptor; public class JobComparator { // stack used to create a message in case of differences found between jobs private Stack<String> stack; /** * if the last 2 jobs compared are not equal, a message will be returned * explaining the first difference encountered. Returns an empty string if * the * */ public String getDifferenceMessage() { return stack.toString(); } /** * * We state that: For any jobs (TaskFlowJob) job1 and job2 such that job1 * serialized to xml produces job1.xml job1.xml loaded in java produces job2 * then isEqual(job1,job2) == true * * @throws ClassNotFoundException * @throws IOException */ public boolean isEqualJob(TaskFlowJob job1, TaskFlowJob job2) throws IOException, ClassNotFoundException { stack = new Stack<>(); stack.push("job"); stack.push("Job attributes"); if (!isEqualCommonAttribute(job1, job2)) return false; stack.pop(); // job attributes if (!isEqualString(job1.getProjectName(), job2.getProjectName(), false)) { stack.push("ProjectName"); return false; } if (!job1.getPriority().equals(job2.getPriority())) { stack.push("Priority"); return false; } if (!job1.getName().equals(job2.getName())) { stack.push("Name"); return false; } if (!isEqualString(job1.getDescription(), job2.getDescription())) { stack.push("Description"); return false; } if (!isEqualString(job1.getInputSpace(), job2.getInputSpace())) { stack.push("Input Space"); return false; } if (!isEqualString(job1.getOutputSpace(), job2.getOutputSpace())) { stack.push("Output Space"); return false; } stack.push("stackflow"); if (!isTaskFlowEqual(job1, job2)) return false; stack.pop(); return true; } private boolean isEqualCommonAttribute(CommonAttribute attrib1, CommonAttribute attrib2) { if (!isEqualUpdatableProperty(attrib1.getOnTaskErrorProperty(), attrib2.getOnTaskErrorProperty())) { stack.push(" CancelJobOnErrorProperty "); return false; } if (!isEqualUpdatableProperty(attrib1.getMaxNumberOfExecutionProperty(), attrib2.getMaxNumberOfExecutionProperty())) { stack.push(" maxNumberOfExecution "); return false; } if (!isEqualUpdatableProperty(attrib1.getRestartTaskOnErrorProperty(), attrib2.getRestartTaskOnErrorProperty())) { stack.push(" RestartTaskOnError "); return false; } stack.push(" genericInformation "); if (!isEqualMap(attrib1.getGenericInformation(), attrib2.getGenericInformation())) { stack.push("generic info 1= " + attrib1.getGenericInformation() + " ----- generic info 2 = " + attrib2.getGenericInformation()); return false; } stack.pop(); // generic informations return true; } private boolean isTaskFlowEqual(TaskFlowJob job1, TaskFlowJob job2) throws IOException, ClassNotFoundException { ArrayList<Task> tasks1 = job1.getTasks(); ArrayList<Task> tasks2 = job2.getTasks(); if (tasks1.size() != tasks2.size()) { stack.push("Sizes don't match"); return false; } // the order of the tasks may not be the same // the tasks have unique name inside a job Map<String, Task> map1 = new HashMap<>(); Map<String, Task> map2 = new HashMap<>(); for (int k = 0; k < tasks1.size(); k++) { map1.put(tasks1.get(k).getName(), tasks1.get(k)); map2.put(tasks2.get(k).getName(), tasks2.get(k)); } for (String name : map1.keySet()) { stack.push("Task " + map1.get(name)); if (!isTaskEqual(map1.get(name), map2.get(name))) return false; stack.pop(); } return true; } private boolean isTaskEqual(Task t1, Task t2) throws IOException, ClassNotFoundException { if ((t1 == null) && (t2 == null)) return true; if ((t1 == null) ^ (t2 == null)) { stack.push("One of 2 tasks is null"); return false; } if (!isEqualCommonAttribute(t1, t2)) return false; if (!t1.getName().equals(t2.getName())) { stack.push("name"); return false; } if (!isEqualString(t1.getDescription(), t2.getDescription())) { stack.push("description"); return false; } if (t1.getWallTime() != t2.getWallTime()) { stack.push("walltime"); return false; } // ****** task dependencies **** stack.push("task dependenices"); List<Task> dep1 = t1.getDependencesList(); List<Task> dep2 = t2.getDependencesList(); if (dep1 == null ^ dep2 == null) { stack.push("one dependency list is empty"); return false; } if (dep1 != null) { if (dep1.size() != dep2.size()) { stack.push("sizes don't match"); return false; } // we only compare the names in the 2 dependencies lists int dep1Size = dep1.size(); Set<String> names1 = new HashSet<String>(dep1Size); Set<String> names2 = new HashSet<String>(dep1Size); for (int k = 0; k < dep1Size; k++) { names1.add(dep1.get(k).getName()); names2.add(dep2.get(k).getName()); } if (!CollectionUtils.isEqualCollection(names1, names2)) { return false; } } stack.pop(); // task dependencies // **** parallel environment **** stack.push("parallel environment"); if (!isEqualParallelEnvironment(t1.getParallelEnvironment(), t2.getParallelEnvironment())) return false; stack.pop(); // parallel env // input files stack.push("input files"); if (!isEqualInputFiles(t1.getInputFilesList(), t2.getInputFilesList())) return false; stack.pop(); stack.push("output files"); if (!isEqualOutputFiles(t1.getOutputFilesList(), t2.getOutputFilesList())) return false; stack.pop(); // scripts stack.push("pre script"); if (!isEqualScript(t1.getPreScript(), t2.getPreScript())) return false; stack.pop(); stack.push("post script"); if (!isEqualScript(t1.getPostScript(), t2.getPostScript())) return false; stack.pop(); stack.push("cleaning script"); if (!isEqualScript(t1.getCleaningScript(), t2.getCleaningScript())) return false; stack.pop(); stack.push("selection scripts"); List<SelectionScript> ss1 = t1.getSelectionScripts(); List<SelectionScript> ss2 = t2.getSelectionScripts(); if ((ss1 == null) ^ (ss2 == null)) { stack.push("One of two lists of selection scripts is null"); return false; } if (ss1 != null) { if (t1.getSelectionScripts().size() != t2.getSelectionScripts().size()) { stack.push("lists size don't match"); return false; } for (int k = 0; k < t1.getSelectionScripts().size(); k++) { if (!isEqualScript(t1.getSelectionScripts().get(k), t2.getSelectionScripts().get(k))) { return false; } } } stack.pop(); // select scripts // flow control if (t1.getFlowBlock() != t2.getFlowBlock()) { stack.push("flow block"); return false; } stack.push("flow control"); if (!isEqualFlowControl(t1.getFlowScript(), t2.getFlowScript())) return false; stack.pop(); // ***** task executable ***** if (!isEqualClass(t1.getClass(), t2.getClass())) { stack.push("Executable types don't match"); return false; } if (t1 instanceof JavaTask) { JavaTask jt1 = (JavaTask) t1; JavaTask jt2 = (JavaTask) t2; stack.push("arguments"); if (!isEqualMap(jt1.getArguments(), jt2.getArguments())) return false; stack.pop(); stack.push("executable class"); if (!isEqualString(jt1.getExecutableClassName(), jt2.getExecutableClassName())) return false; stack.pop(); stack.push("forked environemnt"); if (!isEqualForkedEnvironment(jt1.getForkEnvironment(), jt2.getForkEnvironment())) return false; stack.pop(); } // insttanceof JavaTask if (t1 instanceof NativeTask) { NativeTask nt1 = (NativeTask) t1; NativeTask nt2 = (NativeTask) t2; String[] cl1 = nt1.getCommandLine(); String[] cl2 = nt2.getCommandLine(); if (cl1 == null ^ cl2 == null) { return false; } else if (cl1 != null) { if (!CollectionUtils.isEqualCollection(Arrays.asList(cl1), Arrays.asList(cl2))) { return false; } } } if (t1 instanceof ScriptTask) { ScriptTask st1 = (ScriptTask) t1; ScriptTask st2 = (ScriptTask) t2; if (!isEqualScript(st1.getScript(), st2.getScript())) return false; } return true; } private boolean isEqualForkedEnvironment(ForkEnvironment fe1, ForkEnvironment fe2) { if ((fe1 == null) && (fe2 == null)) return true; if ((fe1 == null) ^ (fe2 == null)) { stack.push("One null value out of 2"); return false; } if (!CollectionUtils.isEqualCollection(fe1.getAdditionalClasspath(), fe2.getAdditionalClasspath())) { stack.push("AdditionalClasspath"); return false; } if (!isEqualScript(fe1.getEnvScript(), fe2.getEnvScript())) { stack.push("EnvScript"); return false; } if (!isEqualString(fe1.getJavaHome(), fe2.getJavaHome())) { stack.push("JavaHome"); return false; } if (!CollectionUtils.isEqualCollection(fe1.getJVMArguments(), fe2.getJVMArguments())) { stack.push("JVMArguments"); return false; } if (!isEqualMap(fe1.getSystemEnvironment(), fe2.getSystemEnvironment())) { stack.push("SystemEnvironment"); return false; } if (!isEqualString(fe1.getWorkingDir(), fe2.getWorkingDir())) { stack.push("WorkingDir"); return false; } // no need to check fe1.getPropertyModifiers() as they are included in // getSystemEnvironment() return true; } private boolean isEqualFlowControl(FlowScript fs1, FlowScript fs2) { if ((fs1 == null) && (fs2 == null)) return true; if ((fs1 == null) || (fs2 == null)) return false; if (!isEqualString(fs1.getActionContinuation(), fs2.getActionContinuation())) return false; if (!isEqualString(fs1.getActionTarget(), fs2.getActionTarget())) return false; if (!isEqualString(fs1.getActionTargetElse(), fs2.getActionTargetElse())) return false; if (!isEqualString(fs1.getActionType(), fs2.getActionType())) return false; if (!isEqualString(fs1.getEngineName(), fs2.getEngineName())) return false; if (!isEqualScript(fs1, fs2)) return false; return true; } private boolean isEqualString(String s1, String s2) { if ((s1 == null) && (s2 == null)) return true; if ((s1 == null) ^ (s2 == null)) { stack.push("One of 2 values is null " + s1 + "!=" + s2); return false; } if (!s1.equals(s2)) { stack.push(s1 + "!= " + s2); return false; } return true; } private boolean isEqualString(String s1, String s2, boolean caseSensitive) { if ((s1 == null) || (s2 == null)) return isEqualString(s1, s2); if (caseSensitive) return isEqualString(s1, s2); else return isEqualString(s1.toLowerCase(), s2.toLowerCase()); } /** * * Rather than comparing the scripts and the parameters, we will inline the * parameters in the script code and then just compare the script text. This * is because the Job2XMLTransformer inlines the script parameters * */ private boolean isEqualScript(Script<?> s1, Script<?> s2) { if ((s1 == null) && (s2 == null)) return true; if ((s1 == null) ^ (s2 == null)) { stack.push("One of 2 scripts is null"); return false; } if (!s1.getEngineName().equals(s2.getEngineName())) { stack.push("engine name"); return false; } String text1 = s1.getScript().trim(); if (s1.getParameters() != null) { text1 = Job2XMLTransformer.inlineScriptParametersInText(text1, s1.getParameters()); } String text2 = s2.getScript().trim(); if (s2.getParameters() != null) { text2 = Job2XMLTransformer.inlineScriptParametersInText(text2, s2.getParameters()); } return text1.equals(text2); } /** * Compares the element in the 2 lists in the exact order they appear in the * lists */ private boolean isEqualInputFiles(List<InputSelector> l1, List<InputSelector> l2) { if ((l1 == null) && (l2 == null)) return true; if ((l1 == null) ^ (l2 == null)) { stack.push("One of 2 values is null"); return false; } if (l1.size() != l2.size()) { stack.push("sizes don't match"); return false; } for (InputSelector is1 : l1) { boolean found = false; for (int i = 0; i < l2.size(); i++) { InputSelector is2 = l2.get(i); if (!is1.getMode().equals(is2.getMode())) { continue; } Set<String> i1 = is1.getInputFiles().getIncludes(); Set<String> i2 = is2.getInputFiles().getIncludes(); if (!i1.equals(i2)) { continue; } Set<String> e1 = is1.getInputFiles().getExcludes(); Set<String> e2 = is2.getInputFiles().getExcludes(); if (!e1.equals(e2)) { continue; } found = true; break; } if (!found) { return false; } } return true; } /** * Compares the element in the 2 lists in the exact order they appear in the * lists FIXME: bad object design in the data space layer provides us to * unify the similar code in this method and isEqualInputFiles */ private boolean isEqualOutputFiles(List<OutputSelector> l1, List<OutputSelector> l2) { if ((l1 == null) && (l2 == null)) return true; if ((l1 == null) ^ (l2 == null)) { stack.push("One of 2 values is null"); return false; } if (l1.size() != l2.size()) return false; for (OutputSelector os1 : l1) { boolean found = false; for (int i = 0; i < l2.size(); i++) { OutputSelector os2 = l2.get(i); if (!os1.getMode().equals(os2.getMode())) { continue; } Set<String> i1 = os1.getOutputFiles().getIncludes(); Set<String> i2 = os2.getOutputFiles().getIncludes(); if (!i1.equals(i2)) { continue; } Set<String> e1 = os1.getOutputFiles().getExcludes(); Set<String> e2 = os2.getOutputFiles().getExcludes(); if (!e1.equals(e2)) { continue; } found = true; break; } if (!found) { return false; } } return true; } private boolean isEqualParallelEnvironment(ParallelEnvironment e1, ParallelEnvironment e2) { if ((e1 == null) && (e2 == null)) return true; if ((e1 == null) ^ (e2 == null)) { stack.push("One value out of 2 is null"); return false; } if (e1.getNodesNumber() != e2.getNodesNumber()) { stack.push("nodes number"); return false; } // check same instance of topology decsriptor TopologyDescriptor topologyDescriptor1 = e1.getTopologyDescriptor(); TopologyDescriptor topologyDescriptor2 = e2.getTopologyDescriptor(); if (topologyDescriptor1 == null && topologyDescriptor2 == null) { return true; } if (topologyDescriptor1 == null ^ topologyDescriptor2 == null) { return isEqualClass(TopologyDescriptor.ARBITRARY.getClass(), (topologyDescriptor1 == null ? topologyDescriptor2.getClass() : topologyDescriptor1.getClass())); } if (!isEqualClass(topologyDescriptor1.getClass(), topologyDescriptor2.getClass())) { stack.push("topology descriptor type"); return false; } if (topologyDescriptor1 instanceof ThresholdProximityDescriptor) { if (!(topologyDescriptor2 instanceof ThresholdProximityDescriptor)) { stack.push("Only one is ThresholdProximityDescriptor type."); return false; } if (((ThresholdProximityDescriptor) topologyDescriptor1) .getThreshold() != ((ThresholdProximityDescriptor) topologyDescriptor2).getThreshold()) { stack.push("ThresholdProximityDescriptor.threshold"); return false; } } return true; } private boolean isEqualMap(Map<?, ?> m1, Map<?, ?> m2) { if ((m1 == null) && (m2 == null)) return true; if ((m1 == null) || (m2 == null)) return false; return m1.equals(m2); } private static <T> boolean isEqualUpdatableProperty(UpdatableProperties<T> property1, UpdatableProperties<T> property2) { return (property1.isSet() ^ property2.isSet()) ? false : ((property1.isSet()) ? property1.getValue().equals(property2.getValue()) : true); } private boolean isEqualClass(Class<?> clazz1, Class<?> clazz2) { return clazz1.getName().equals(clazz2.getName()); } }