package Sequenic.T2.Coverage; import java.io.ObjectStreamException; import java.io.Serializable; import java.util.Arrays; import java.util.Map; import java.util.WeakHashMap; /** * A simple class to represent a path through a method. * * @author Jeiel Schalkwijk * */ public final class BasicPath implements Serializable{ private static final long serialVersionUID = 1772935939580951218L; private final String methodName; private final int[] path; private final int hashCode; /** It is assumed that all ints in the path fall in range [0..65535]. * This condition is checked by Sequenic.Graph.Vertex.setId(). * * @param methodName * @param path */ BasicPath(String methodName, int[] path) { this.methodName = methodName; this.path = path; hashCode = methodName.hashCode()+Arrays.hashCode(path); } public String getMethodUname() { return methodName; } public int[] getNodes() { return path; } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object obj) { if(obj==this) return true; else if(obj instanceof BasicPath) { BasicPath x = (BasicPath) obj; return x.methodName.equals(methodName) && Arrays.equals(path, x.path); } else return false; } @Override public String toString() { return methodName +": "+ Arrays.toString(path); } // public boolean cachedSelect(Selector selector) // { // return cachedSelectAndUpdate(selector)==null; // } // // /** // * Returns null if this BasicPath is modification-traversing according to the selector. // * Otherwise it returns the relabeled version of the BasicPath. // * If no nodes require relabeling it will return this. // * // * The result is cached and reused for future calls // * that use the same selector object. // * // * @param selector // * @return // */ // public BasicPath cachedSelectAndUpdate(Selector selector) // { // if(selector!=cachedSelector) // { // //First call to this selector // cachedSelector = selector; // return (cachedReplacement = selector.selectAndUpdate(this)); // } else // { // //cached call // return cachedReplacement; // } // } // // // private transient BasicPath cachedReplacement; // private transient Selector cachedSelector; // // /** // * An interface for BasicPath Selectors. // */ // public static interface Selector // { // /** Return null if p is modification-traversing. // * // * Return a BasicPath object with relabeled nodes if test is not modification-traversing. // * If no nodes need relabeling return p. // * // * // * @param p // * @return // */ // public BasicPath selectAndUpdate(BasicPath p); // // public boolean justSelect(BasicPath p); // } /** If multiple trace files are merged, it becomes possible that * distinct but equal (i.e. duplicate) BasicPath objects are written. * If nothing is done, over time the number of duplicate BasicPath objects in a stream could grow. * * The following method prevents this from happening. * The first time a unique BasicPath is encountered, it is returned and written to the stream. * * Any subsequent duplicates will return the first unique version. * Java's serialization mechanism will then recognize the Object as a previously serialized Object * and all references to the duplicate will be replaced, in the stream, with references to the * returned, and already serialized, object. */ private Object writeReplace() throws ObjectStreamException{ return cached(); } private Object readResolve() throws ObjectStreamException{ return cached(); } private static final Map weakCache = new WeakHashMap(); private BasicPath cached() { synchronized (weakCache) { BasicPath bp = weakCache.get(this); if(bp!=null) return bp; weakCache.put(this,this); return this; } } /** Factory method to create BasicPaths. * If an existing equivalent BasicPath already exists it is returned, * otherwise a new BasicPath is returned. * * It is assumed that all int values in the path fall in range [0..65535]. * This condition is checked by Sequenic.Graph.Vertex.setId(). * * @param methodName * @param path * @return */ public static BasicPath create(String methodName, int[] path) { return new BasicPath(methodName, path).cached(); } }