View Javadoc

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.sdedit;
24  
25  import java.io.File;
26  import java.io.FileWriter;
27  import java.io.IOException;
28  import java.io.Writer;
29  import java.util.ArrayList;
30  import java.util.List;
31  
32  import th.co.edge.jseq.Activation;
33  import th.co.edge.jseq.ActivationList;
34  import th.co.edge.jseq.Diagram;
35  
36  /**
37   * An <code>SdeditTextDiagram</code> is a <code>Diagram</code> that can be
38   * used to generate sequence diagrams as text files that can be read by the <a
39   * href="http://sdedit.sourceforge.net/" target="new">Quick Sequence Diagram
40   * Editor</a>.
41   */
42  public class SdeditTextDiagram implements Diagram {
43      private static final String NEW_LINE = "\n";
44      private ActivationList activationList;
45  
46      /**
47       * Creates a new <code>SdeditTextDiagram</code>, using the given
48       * <code>ActivationList</code> as the basis for the sequence diagram.
49       * 
50       * @param activationList
51       *            a list of root <code>Activation</code>s to use when
52       *            generating the sequence diagram
53       */
54      public SdeditTextDiagram(ActivationList activationList) {
55          this.activationList = activationList;
56      }
57  
58      /**
59       * Creates a textual description of a sequence diagram understandable by the
60       * <a href="http://sdedit.sourceforge.net/" target="new">Quick Sequence
61       * Diagram Editor</a>, and saves it to a text file.
62       * 
63       * @param file
64       *            the <code>File</code> to write to
65       * 
66       * @throws IOException
67       *             if something went wrong when creating or saving the diagram
68       */
69      @Override
70      public void save(File file) throws IOException {
71          FileWriter writer = null;
72          try {
73              writer = new FileWriter(file);
74              writeDiagram(writer);
75          } finally {
76              if (writer != null) {
77                  writer.close();
78              }
79          }
80      }
81  
82      /**
83       * Same as the <code>save</code> method, but writes to a
84       * <code>Writer</code> instead of to a <code>File</code>. This is
85       * useful when testing.
86       * 
87       * @param writer
88       *            the <code>Writer</code> to write to
89       * 
90       * @throws IOException
91       *             if something went wrong when creating or writing the diagram
92       * 
93       * @see #save(File)
94       */
95      void writeDiagram(Writer writer) throws IOException {
96          writeActorsAndObjectNames(writer);
97          writer.write(NEW_LINE);
98  
99          int index = 1;
100         for (Activation activation : activationList) {
101             writeActivation(activation, index, writer);
102             writer.write(NEW_LINE);
103             index++;
104         }
105     }
106 
107     private void writeActorsAndObjectNames(Writer writer) throws IOException {
108         int index = 1;
109         for (Activation activation : activationList) {
110             writer.write("Actor" + index + ":Actor");
111             writer.write(NEW_LINE);
112             writeObjectNames(activation, writer, index, new ArrayList<String>());
113             index++;
114         }
115     }
116 
117     private void writeObjectNames(Activation activation, Writer writer,
118             int index, List<String> objectNames) throws IOException {
119         String objectName = getObjectName(activation, index);
120         if (!objectNames.contains(objectName)) {
121             objectNames.add(objectName);
122             writer.write(objectName);
123             writer.write(":");
124             writer.write(getClassName(activation));
125             writer.write("[a]");
126             writer.write(NEW_LINE);
127         }
128         for (Activation nestedActivation : activation.getNestedActivations()) {
129             writeObjectNames(nestedActivation, writer, index, objectNames);
130         }
131     }
132 
133     private void writeActivation(Activation activation, int index, Writer writer)
134             throws IOException {
135         writer.write("Actor" + index);
136         writer.write(":");
137         writer.write(getObjectName(activation, index));
138         writer.write(".");
139         writer.write(getMethodName(activation));
140         writer.write(NEW_LINE);
141         for (Activation nestedActivation : activation.getNestedActivations()) {
142             writeActivation(nestedActivation, index, 1, writer);
143         }
144         writer.write(getObjectName(activation, index) + ":stop");
145     }
146 
147     private void writeActivation(Activation activation, int index,
148             int nestingLevel, Writer writer) throws IOException {
149         indent(writer, nestingLevel);
150         writer.write(getObjectName(activation.getParent(), index));
151         writer.write(":");
152         writer.write(getObjectName(activation, index));
153         writer.write(".");
154         writer.write(getMethodName(activation));
155         writer.write(NEW_LINE);
156 
157         for (Activation nestedActivation : activation.getNestedActivations()) {
158             writeActivation(nestedActivation, index, nestingLevel + 1, writer);
159         }
160     }
161 
162     private void indent(Writer writer, int depth) throws IOException {
163         for (int i = 0; i < depth; i++) {
164             writer.write("  ");
165         }
166     }
167 
168     private String getObjectName(Activation activation, int index) {
169         return getClassName(activation).toLowerCase() + index;
170     }
171 
172     private String getClassName(Activation activation) {
173         String qualifiedClassName = activation.getClassName();
174         int lastDot = qualifiedClassName.lastIndexOf('.');
175         String result = qualifiedClassName.substring(lastDot + 1);
176         if (result.contains("$")) {
177             int lastInnerClassSeperator = result.lastIndexOf('$');
178             result = result.substring(lastInnerClassSeperator + 1);
179         }
180         return result;
181     }
182 
183     private String getMethodName(Activation activation) {
184         String methodName = activation.getMethod().name();
185         return methodName;
186     }
187 
188     /**
189      * Returns a string representation of this <code>SdeditTextDiagram</code>,
190      * currently in the form of comma-separated list of the root activations,
191      * <b>not</b> in the same form written to a file using the
192      * <code>save</code> method. This may change in the future.
193      * 
194      * @return a string representation of this <code>SdeditTextDiagram</code>
195      */
196     @Override
197     public String toString() {
198         return activationList.toString();
199     }
200 }