View Javadoc

1   /*
2    * Copyright 2006-2010 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sourceforge.domian.util;
17  
18  
19  import java.io.PrintStream;
20  import java.io.PrintWriter;
21  import java.io.StringWriter;
22  import java.io.Writer;
23  import java.util.Formatter;
24  import java.util.HashMap;
25  import java.util.Map;
26  import java.util.StringTokenizer;
27  
28  import net.sourceforge.domian.entity.Entity;
29  import net.sourceforge.domian.repository.PartitionRepository;
30  import net.sourceforge.domian.repository.PersistentRepository;
31  import net.sourceforge.domian.specification.Specification;
32  
33  import static java.lang.Runtime.getRuntime;
34  import static java.lang.Thread.currentThread;
35  import static org.apache.commons.lang.StringUtils.isBlank;
36  import static org.apache.commons.lang.StringUtils.repeat;
37  import static org.apache.commons.lang.SystemUtils.LINE_SEPARATOR;
38  
39  
40  /**
41   * Some convenient instrumentation methods and constants.
42   *
43   * @author Eirik Torske
44   * @since 0.4
45   */
46  public class InstrumentationUtils {
47  
48      public static final String DOTS = "...";
49      public static final String NOT_SUPPORTED = "NOT SUPPORTED";
50      public static final String NOT_YET_SUPPORTED = "NOT YET SUPPORTED";
51      public static final String REDEFINED_ELSEWHERE = "REDEFINED ELSEWHERE";
52      public static final String REDEFINED = "REDEFINED";
53      public static final String NOT_APPLICABLE = "N/A";
54      public static final String SKIPPED = "SKIPPED";
55      public static final String TODO = "TODO";
56      public static final String TEMPORARILY_ISOLATED = "TEMPORARILY RELOCATED JUST TO RUN TEST ISOLATED";
57      public static final String TEMPORARY = "TEMPORARY";
58  
59      public static final String DEBUG_LEVEL_INDENTATION = repeat(" ", 3);
60      public static final String TRACE_LEVEL_INDENTATION = repeat(DEBUG_LEVEL_INDENTATION, 2);
61  
62  
63      public static String buildTestingOfMethodString(final String methodName) {
64          return buildTestingOfMethodString(methodName, null);
65      }
66  
67  
68      /** <code>testTarget</code> parameter to be used wherever test methods are inherited. */
69      public static String buildTestingOfMethodString(final Object testTarget, final String methodName) {
70          return buildTestingOfMethodString(testTarget, methodName, null);
71      }
72  
73  
74      /** <code>testTarget</code> parameter to be used wherever test methods are inherited. */
75      public static String buildTestingOfMethodString(final Object instance, final String methodName, final String deviation) {
76          return isBlank(deviation) ? "Testing " + buildSimpleClassMethodString(instance, methodName) + DOTS : "Testing " + methodName + " " + DOTS + " [" + deviation + "]";
77      }
78  
79  
80      public static String buildSimpleClassMethodString(final Object instance, final String methodName) {
81          return instance.getClass().getSimpleName() + "." + methodName + "()";
82      }
83  
84  
85      public static String buildDebugLogLevelIterationMessage(final int iterationNumber, final Object instance, final String methodName) {
86          return DEBUG_LEVEL_INDENTATION + "#" + iterationNumber + " [" + buildSimpleClassMethodString(instance, methodName) + "]";
87      }
88  
89  
90      public static String buildThreadNumberAndMessage(final String message) {
91          final Formatter formatter = new Formatter();
92          formatter.format("#%-6d" + message, currentThread().getId());
93          return formatter.toString();
94      }
95  
96  
97      public static String buildThreadNumberAndMessage(final Object instance,
98                                                       final String methodName,
99                                                       final String message) {
100         final Formatter formatter = new Formatter();
101         formatter.format("#%-6d", currentThread().getId());
102         formatter.format("%-75s", instance.getClass().getName() + "[" + instance.hashCode() + "]." + methodName + "()");
103         formatter.format("   ");
104         formatter.format(message);
105         return formatter.toString();
106     }
107 
108 
109     /** @return a string with format [mem: &lt;used memory in MB&gt;/&lt;free memory in MB&gt;] */
110     public static String buildMemoryConsumptionMessage() {
111         return "[mem: " + (getRuntime().totalMemory() - getRuntime().freeMemory()) / 1000000 + "MB/" + getRuntime().totalMemory() / 1000000 + "MB]";
112     }
113 
114 
115     /**
116      * @param numberOfStackTraceLines the number of stack trace lines wanted
117      * @param skipLines               the number of stack trace lines to skip, counting from the top
118      * @return indented stack trace lines generated by the JVM
119      */
120     public static String getStackTrace(final Integer numberOfStackTraceLines, final Integer skipLines) {
121         return getStackTrace(new RuntimeException("Provoked by net.sourceforge.domian.util.InstrumentationUtils.getStackTrace()"),
122                              numberOfStackTraceLines,
123                              skipLines + 1);
124     }
125 
126 
127     /**
128      * @param throwable               the thrown exception to harvest stacktrace from
129      * @param numberOfStackTraceLines the number of stack trace lines wanted
130      * @param skipLines               the number of stack trace lines to skip, counting from the top
131      * @return indented stack trace lines generated by the JVM
132      */
133     public static String getStackTrace(final Throwable throwable, final Integer numberOfStackTraceLines, final Integer skipLines) {
134         final Writer stringWriter = new StringWriter();
135         throwable.printStackTrace(new PrintWriter(stringWriter));
136         final StringTokenizer stringTokenizer = new StringTokenizer(stringWriter.toString(), LINE_SEPARATOR);
137         final StringBuilder stringBuilder = new StringBuilder();
138         int printedElementIndex;
139         for (int elementIndex = printedElementIndex = 0;
140              stringTokenizer.hasMoreElements() && printedElementIndex < numberOfStackTraceLines;
141              ++elementIndex) {
142             final Object nextElement = stringTokenizer.nextElement();
143             if (elementIndex >= skipLines) {
144                 stringBuilder.append(nextElement).append(LINE_SEPARATOR);
145                 ++printedElementIndex;
146             }
147         }
148         return stringBuilder.toString();
149     }
150 
151 
152     /**
153      * Builds a message containing a trailing stack trace.
154      *
155      * @param message                 message to print to <code>System.err</code>
156      * @param numberOfStackTraceLines the number of stack trace lines wanted
157      * @param skipLines               the number of stack trace lines to skip, counting from the top
158      * @return the constructed message
159      */
160     public static String buildMessageWithStackTrace(final String message,
161                                                     final Integer numberOfStackTraceLines,
162                                                     final int skipLines) {
163         final StringBuilder messageBuilder = new StringBuilder();
164         messageBuilder.append(message);
165         if (numberOfStackTraceLines > 0) {
166             messageBuilder.append(LINE_SEPARATOR);
167             messageBuilder.append(getStackTrace(numberOfStackTraceLines, skipLines));
168         }
169         return messageBuilder.toString();
170     }
171 
172 
173     /**
174      * Builds a message containing a trailing stack trace.
175      *
176      * @param throwable               the thrown exception to harvest stacktrace from
177      * @param message                 message to print to <code>System.err</code>
178      * @param numberOfStackTraceLines the number of stack trace lines wanted
179      * @param skipLines               the number of stack trace lines to skip, counting from the top
180      * @return the constructed message
181      */
182     public static String buildMessageWithStackTrace(final Throwable throwable,
183                                                     final String message,
184                                                     final Integer numberOfStackTraceLines,
185                                                     final int skipLines) {
186         final StringBuilder messageBuilder = new StringBuilder();
187         messageBuilder.append(message);
188         if (numberOfStackTraceLines > 0) {
189             messageBuilder.append(LINE_SEPARATOR);
190             messageBuilder.append(getStackTrace(throwable, numberOfStackTraceLines, skipLines));
191         }
192         return messageBuilder.toString();
193     }
194 
195 
196     /** US-style pretty-printing of large numbers, adding a comma for every thousand. */
197     public static String prettyPrintLargeNumber(final long bigNumber) {
198         final char[] number = Long.toString(bigNumber).toCharArray();
199         final StringBuilder builder = new StringBuilder(Long.toString(bigNumber));
200         int reverseIndex = 0;
201         for (int i = number.length; i >= 0; --i) {
202             if ((++reverseIndex % 3 == 0) && (i > 1)) {
203                 builder.insert(i - 1, ',');
204             }
205         }
206         return builder.toString();
207     }
208 
209 
210     /** Instrumentation of partition repo structure. */
211     public static void printPartitionRepository(final PartitionRepository repo, final PrintStream printStream) {
212         printStream.println();
213         printStream.println("Root partition:  " + DEBUG_LEVEL_INDENTATION + printPartitionRepoId(repo) + " " +
214                             printPartitionRepoType(repo) + " " +
215                             printPartitionRepoOnlyNumberOfEntities(repo) + " " +
216                             printPartitionSpecification(repo));
217         final Map<Specification<? extends Entity>, PartitionRepository> partitions = new HashMap<Specification<? extends Entity>, PartitionRepository>();
218         repo.collectAllPartitions(partitions);
219         int partitionIndex = 0;
220         for (final PartitionRepository partitionRepo : partitions.values()) {
221             printStream.println(DEBUG_LEVEL_INDENTATION + "Sub partition " + ++partitionIndex + ": " +
222                                 printPartitionRepoId(partitionRepo) + " " +
223                                 printPartitionRepoType(partitionRepo) + " " +
224                                 printPartitionRepoOnlyNumberOfEntities(partitionRepo) + " " +
225                                 printPartitionSpecification(partitionRepo));
226         }
227     }
228 
229 
230     private static String printPartitionRepoId(final PartitionRepository partitionRepo) {
231         final StringBuilder stringBuilder = new StringBuilder();
232         stringBuilder.append("[");
233         if (partitionRepo instanceof PersistentRepository) {
234             stringBuilder.append(((PersistentRepository) partitionRepo).getRepositoryId());
235         } else {
236             stringBuilder.append("<not persistent/no repo id>");
237         }
238         stringBuilder.append("]");
239         return stringBuilder.toString();
240     }
241 
242 
243     private static String printPartitionRepoType(final PartitionRepository partitionRepo) {
244         return "[" + partitionRepo.getTargetRepository().getClass().getSimpleName() + "]";
245     }
246 
247 
248     private static String printPartitionRepoOnlyNumberOfEntities(final PartitionRepository partitionRepo) {
249         return "[" + partitionRepo.getPartitionOnlyEntities().size() + " entities]";
250     }
251 
252 
253     private static String printPartitionSpecification(final PartitionRepository partitionRepo) {
254         final StringBuilder stringBuilder = new StringBuilder();
255         stringBuilder.append("[");
256         Specification partitionSpecification = partitionRepo.getPartitionSpecification();
257         if (partitionSpecification != null) {
258             stringBuilder.append(partitionSpecification.toString());
259             // TODO v0.5.1: fix this...
260             //return "[" + partitionRepo.getPartitionSpecification().specificationToString() + "]";
261 
262         } else {
263             stringBuilder.append("<no partition specification>");
264         }
265         stringBuilder.append("]");
266         return stringBuilder.toString();
267     }
268 }