View Javadoc

1   // Copyright (C) 2000 - 2011 Philip Aston
2   // All rights reserved.
3   //
4   // This file is part of The Grinder software distribution. Refer to
5   // the file LICENSE which is part of The Grinder distribution for
6   // licensing details. The Grinder distribution is available on the
7   // Internet at http://grinder.sourceforge.net/
8   //
9   // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12  // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
13  // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
14  // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
15  // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16  // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
17  // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
18  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
19  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
20  // OF THE POSSIBILITY OF SUCH DAMAGE.
21  
22  package net.grinder.statistics;
23  
24  
25  /**
26   * <p>
27   * Associate a statistic expression with display information.
28   * </p>
29   *
30   * <p>
31   * Statistic expressions are composed of statistic names (see
32   * {@link StatisticsIndexMap}) in a simple post-fix format using the symbols
33   * <code>+</code>, <code>-</code>, <code>/</code> and <code>*</code>,
34   * which have their usual meanings, in conjunction with simple statistic names
35   * or sub-expressions. Precedence can be controlled by grouping expressions in
36   * parentheses. For example, the error rate is
37   * <code>(* (/ errors period) 1000)</code> errors per second.
38   * </p>
39   *
40   * <p>
41   * Sample statistics, such as <em>timedTests</em>, must be introduced with
42   * one of <code>sum</code>, <code>count</code>, or <code>variance</code>,
43   * depending on the attribute of interest.
44   * </p>
45   *
46   * <p>
47   * For example, the statistic expression <code>(/ (sum timedTests)
48   * (count timedTests))</code>
49   * represents the mean test time in milliseconds.
50   *
51   * @author Philip Aston
52   */
53  public final class ExpressionView {
54  
55    private static int s_creationOrder;
56  
57    private final String m_displayName;
58    private final String m_expressionString;
59    private final boolean m_showForCompositeStatistics;
60    private final int m_hashCode;
61    private final int m_creationOrder;
62  
63    private final StatisticExpression m_expression;
64  
65    ExpressionView(String displayName,
66                   String expressionString,
67                   StatisticExpression expression,
68                   boolean showForCompositeStatistics) {
69      m_displayName = displayName;
70      m_expressionString = expressionString;
71      m_showForCompositeStatistics = showForCompositeStatistics;
72      m_expression = expression;
73  
74      m_hashCode =
75        m_displayName.hashCode() ^
76        (expressionString != null ? m_expressionString.hashCode() : 0);
77  
78      // Code outside this package can only obtain ExpressionViews through a
79      // StatisticExpressionFactory instance, and in turn this factory must be
80      // obtained from the singleton StatisticServices instance.
81      // StatisticsServicesImplementation creates the common statistics views in
82      // a static block, so we can rely on creation order to ensure that the
83      // standard views are ordered before script defined views.
84      synchronized (ExpressionView.class) {
85        m_creationOrder = s_creationOrder++;
86      }
87    }
88  
89    /**
90     * Get the common display name.
91     *
92     * @return The display name.
93     */
94    public String getDisplayName() {
95      return m_displayName;
96    }
97  
98    /**
99     * Return the {@link StatisticExpression}.
100    *
101    * @return The {@link StatisticExpression}.
102    */
103   public StatisticExpression getExpression() {
104     return m_expression;
105   }
106 
107   /**
108    * Return the expression string.
109    *
110    * @return The string, or <code>null</code> if this view was built directly
111    *         from a {@link StatisticExpression}.
112    */
113   public String getExpressionString() {
114     return m_expressionString;
115   }
116 
117   /**
118    * Return whether this view is relevant for totals of composite statistics.
119    * Many views (particularly those representing aggregate time, or averages)
120    * are ambiguous for composite statistics, so we don't show them.
121    *
122    * @return <code>true</code> => show this view for composite statistics.
123    */
124   public boolean getShowForCompositeStatistics() {
125     return m_showForCompositeStatistics;
126   }
127 
128   /**
129    * Value based equality.
130    *
131    * @param other An <code>Object</code> to compare.
132    * @return <code>true</code> => <code>other</code> is equal to this object.
133    */
134   public boolean equals(Object other) {
135     if (other == this) {
136       return true;
137     }
138 
139     if (other == null || other.getClass() != ExpressionView.class) {
140       return false;
141     }
142 
143     final ExpressionView otherView = (ExpressionView)other;
144 
145     return
146       m_hashCode == otherView.m_hashCode &&
147       m_displayName.equals(otherView.m_displayName) &&
148 
149       // If either expression string is null, one of the views
150       // is not externalisable. If so, we only compare on the
151       // display names.
152       (m_expressionString == null ||
153        otherView.m_expressionString == null ||
154        m_expressionString.equals(otherView.m_expressionString));
155   }
156 
157   /**
158    * Implement {@link Object#hashCode}.
159    *
160    * @return an <code>int</code> value
161    */
162   public int hashCode() {
163     return m_hashCode;
164   }
165 
166   /**
167    * Return a <code>String</code> representation of this
168    * <code>ExpressionView</code>.
169    *
170    * @return The <code>String</code>
171    */
172   public String toString() {
173     final StringBuilder result = new StringBuilder(32);
174     result.append("ExpressionView(");
175     result.append(m_displayName);
176 
177     if (m_expressionString != null) {
178       result.append(", ");
179       result.append(m_expressionString);
180     }
181 
182     result.append(")");
183 
184     return result.toString();
185   }
186 
187   int getCreationOrder() {
188     return m_creationOrder;
189   }
190 }