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 }