1 /* 2 * Copyright (c) 2003-2008, by Henrik Arro and Contributors 3 * 4 * This file is part of JSeq, a tool to automatically create 5 * sequence diagrams by tracing program execution. 6 * 7 * See <http://jseq.sourceforge.net> for more information. 8 * 9 * JSeq is free software: you can redistribute it and/or modify 10 * it under the terms of the GNU Lesser General Public License as 11 * published by the Free Software Foundation, either version 3 of 12 * the License, or (at your option) any later version. 13 * 14 * JSeq is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public License 20 * along with JSeq. If not, see <http://www.gnu.org/licenses/>. 21 */ 22 23 package th.co.edge.jseq; 24 25 import com.sun.jdi.Method; 26 27 /** 28 * An <code>Activation</code> represents one method call, or in other words, 29 * one stack frame. 30 */ 31 public class Activation implements java.io.Serializable { 32 private static final long serialVersionUID = -774147570250028530L; 33 private static final int INDENT_SIZE = 4; 34 35 private Activation parent; 36 private String className; 37 private Method method; 38 private int frameCount; 39 private int numRepetitions = 1; 40 private ActivationList nestedActivations = new ActivationList(); 41 42 /** 43 * Creates a new <code>Activation</code> instance, representing a certain 44 * method call. 45 * 46 * @param parent 47 * the <code>Activation</code> representing the method that 48 * called this method, or <code>null</code> if this is a root 49 * activation. The newly created <code>Activation</code> will 50 * be added as a nested activation of <code>parent</code> 51 * @param className 52 * the name of the class that this method call belongs to 53 * @param method 54 * the <code>Method</code> that is being called 55 * @param frameCount 56 * the index number of the stack frame associated with this 57 * <code>Association</code> 58 */ 59 public Activation(Activation parent, String className, Method method, 60 int frameCount) { 61 this.parent = parent; 62 this.className = className; 63 this.method = method; 64 this.frameCount = frameCount; 65 if (parent != null) { 66 parent.add(this); 67 } 68 } 69 70 /** 71 * Performs a deep copy of this <code>Activation</code> instance. 72 * 73 * @param parentOfCopy 74 * the <code>Activation</code> representing the method that 75 * called this method, potentially different from the original, 76 * or <code>null</code> if the copy is a root activation. The 77 * newly created <code>Activation</code> will be added as a 78 * nested activation of <code>parentOfCopy</code> 79 * 80 * @return a copy of this <code>Activation</code> instance 81 */ 82 public Activation copy(Activation parentOfCopy) { 83 Activation copy = 84 new Activation(parentOfCopy, getClassName(), getMethod(), 85 getFrameCount()); 86 for (Activation child : nestedActivations) { 87 child.copy(copy); 88 } 89 return copy; 90 } 91 92 /** 93 * Returns the <code>Activation</code> that called this 94 * <code>Activation</code>, or <code>null</code> if this is a root 95 * activation. 96 * 97 * @return the caller of this <code>Activation</code> 98 */ 99 public Activation getParent() { 100 return parent; 101 } 102 103 /** 104 * Sets the <code>Activation</code> that called this 105 * <code>Activation</code>. 106 * 107 * @param parent 108 * the caller of this <code>Activation</code>, or 109 * <code>null</code> if this is a root activation 110 */ 111 public void setParent(Activation parent) { 112 this.parent = parent; 113 } 114 115 /** 116 * Returns the name of the class that this <code>Activation</code> belongs 117 * to. 118 * 119 * @return the class name of this <code>Activation</code> 120 */ 121 public String getClassName() { 122 return className; 123 } 124 125 /** 126 * Returns the <code>Method</code> that is being called by this 127 * <code>Activation</code>. 128 * 129 * @return the <code>Method</code> represented by this 130 * <code>Activation</code> 131 */ 132 public Method getMethod() { 133 return method; 134 } 135 136 /** 137 * Returns the index number of the stack frame associated with this 138 * <code>Association</code>. 139 * 140 * @return the index number of this stack frame 141 */ 142 public int getFrameCount() { 143 return frameCount; 144 } 145 146 /** 147 * Returns the number of times the method represented by this 148 * <code>Activation</code> is being called consecutively, with no other 149 * calls in between. If this number is greater than one, it may be 150 * represented in a sequence diagram in some special way, e.g., "*[3]" for 151 * three repetitions. 152 * 153 * @return the number of consecutive calls to this method 154 */ 155 public int getNumRepetitions() { 156 return numRepetitions; 157 } 158 159 /** 160 * Increases the number of consecutive calls of this method by one. 161 */ 162 public void increaseNumRepetitions() { 163 numRepetitions++; 164 } 165 166 /** 167 * Adds another nested <code>Activation</code> to this 168 * <code>Activation</code>. This represents a method call made by this 169 * method. 170 * 171 * @param nestedActivation 172 * the nested <code>Activation</code> to add to this 173 * <code>Activation</code> 174 */ 175 public void add(Activation nestedActivation) { 176 nestedActivations.add(nestedActivation); 177 } 178 179 /** 180 * Returns an <code>ActivationList</code> with all nested 181 * <code>Activation</code>s, that is, all methods called by this method. 182 * 183 * @return an <code>ActivationList</code> with all nested activations. 184 */ 185 public ActivationList getNestedActivations() { 186 return nestedActivations; 187 } 188 189 /** 190 * Sets the <code>ActivationList</code> with all nested 191 * <code>Activation</code>s called by this method. 192 * 193 * @param nestedActivations 194 * the new <code>ActivationList</code> with nested activations. 195 */ 196 public void setNestedActivations(ActivationList nestedActivations) { 197 this.nestedActivations = nestedActivations; 198 } 199 200 /** 201 * Returns the number of nested activations. 202 * 203 * @return the number of method calls made by this activation. 204 */ 205 public int getNumCalls() { 206 return nestedActivations.size(); 207 } 208 209 /** 210 * Returns a string representation of this <code>Activation</code> and all 211 * its nested <code>Activation</code>s, with each activation on a 212 * separate line, and nested activations indented. 213 * 214 * @return a string representation of this <code>Activation</code> 215 */ 216 @Override 217 public String toString() { 218 return toString(0); 219 } 220 221 /** 222 * As <code>toString()</code>, but indents the first activation a given 223 * number of spaces. 224 * 225 * @param indent 226 * the number of spaces to indent the first activation 227 * 228 * @return a string representation of this <code>Activation</code>, with 229 * the first indented <code>indent</code> number of spaces, and 230 * nested activations further indented 231 */ 232 public String toString(int indent) { 233 StringBuffer s = new StringBuffer(); 234 indent(s, indent); 235 s.append(getClassName() + "."); 236 s.append(getMethod().name()); 237 if (getNumRepetitions() > 1) { 238 s.append(" (x " + getNumRepetitions() + ")"); 239 } 240 s.append("\n"); 241 for (Activation nestedActivation : nestedActivations) { 242 s.append(nestedActivation.toString(indent + INDENT_SIZE)); 243 } 244 return s.toString(); 245 } 246 247 private void indent(StringBuffer s, int indent) { 248 for (int i = 0; i < indent; i++) { 249 s.append(" "); 250 } 251 } 252 253 /** 254 * Compares this <code>Activation</code> to another object, and returns 255 * <code>true</code> if and only if the other object is an 256 * <code>Activation</code> with the same class and method names, and equal 257 * nested activations. 258 * 259 * @param o 260 * the object to compare this <code>Activation</code> to 261 * 262 * @return <code>true</code> if <code>o</code> is an 263 * <code>Activation</code> with the same class and method names 264 * and the equal nested activations, <code>false</code> otherwise 265 */ 266 @Override 267 public boolean equals(Object o) { 268 boolean equal = false; 269 if (o instanceof Activation) { 270 Activation otherActivation = (Activation) o; 271 equal = 272 className.equals(otherActivation.className) && 273 method.name().equals(otherActivation.method.name()) && 274 nestedActivations 275 .equals(otherActivation.nestedActivations); 276 } 277 return equal; 278 } 279 280 /** 281 * Returns a hash code for this <code>Activation</code>. 282 * 283 * @return a hash code for this <code>Activation</code> 284 */ 285 @Override 286 public int hashCode() { 287 int result = 17; 288 result = 31 * result + className.hashCode(); 289 result = 31 * result + method.name().hashCode(); 290 result = 31 * result + nestedActivations.hashCode(); 291 return result; 292 } 293 294 }