View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.monitoring;
19  
20  import java.util.Collection;
21  
22  
23  /**
24   * A <code>Monitor</code> is an abstraction of some application resource that
25   * is instrumented with a set of indicators (Gauges or Counters).
26   * <p>
27   * A Monitor is identified by its Key, that MUST be unique in the application.
28   * To ensure this, the Key class defines the monitor identifier as a combination
29   * of name, subsystem and category.
30   * <p>
31   * The <tt>name</tt> is the human-readable representation of the "resource"
32   * beeing monitored. A typical use is the fully qualified class name + method
33   * signature, or the HTTP request path.
34   * <p>
35   * The <tt>category</tt> is a grouping attribute to reflect the application
36   * layering. Typically for JEE application, you will set category to the N-tier
37   * layer beeing monitored ("servlet", "service", "persistence").
38   * <p>
39   * The <tt>subsystem</tt> is a logical grouping, by use-cases. "account", and
40   * "user" can be used as subsystem for the application account and user
41   * management dedicated components.
42   * <p>
43   * You are free to use more complex Key types, by simple subclassing the Key
44   * class and providing the adequate equals()/hasCode() methods.
45   * <p>
46   * The Counters / Gauges used to store monitored application state are retrieved
47   * based on a "role" String. The monitor can handle as many values as needed,
48   * until any of them has a dedicated role. This allows to easily extend the
49   * monitor by registering custom values.
50   *
51   * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
52   */
53  public interface Monitor
54  {
55      /** default role key for code performances */
56      Role<Counter> PERFORMANCES = new Role<Counter>( "performances", Unit.NANOS, Counter.class );
57  
58      /** default role for multi-thread concurrency */
59      Role<Gauge> CONCURRENCY = new Role<Gauge>( "concurrency", Unit.UNARY, Gauge.class );
60  
61      /** default Role for the invocation failure counter */
62      Role<Counter> FAILURES = new Role<Counter>( "failures", Unit.UNARY, Counter.class );
63  
64      /**
65       * @return the monitor key
66       */
67      Key getKey();
68  
69      /**
70       * Retrieve a Counter
71       *
72       * @param role a unique identifier for a Counter in the monitor
73       * @param unit the data unit to count
74       * @return the Counter
75       */
76      Counter getCounter( String role );
77  
78      /**
79       * Retrieve or create a Counter in the monitor
80       *
81       * @param role the Counter role in the monitor
82       * @return the Counter
83       */
84      Counter getCounter( Role<Counter> role );
85  
86      /**
87       * Retrieve a Gauge in the monitor
88       *
89       * @param role a unique identifier for a Gauge in the monitor
90       * @return the Gauge
91       */
92      Gauge getGauge( String role );
93  
94      /**
95       * Retrieve or create a Gauge in the monitor
96       *
97       * @param role the gauge role in the monitor
98       * @return the Gauge
99       */
100     Gauge getGauge( Role<Gauge> role );
101 
102     /**
103      * Retrieve a StatValue.
104      *
105      * @param role a unique identifier for a StatValue in the monitor
106      * @return the StatValue
107      */
108     StatValue getValue( String role );
109 
110     /**
111      * Retrieve a StatValue in the monitor
112      *
113      * @param role the StatValue role in the monitor
114      * @return the StatValue
115      */
116     <T extends StatValue> T getValue( Role<T> role );
117 
118     /**
119      *
120      * @return an unmodifiable collection of registered statValues roles
121      */
122     @SuppressWarnings("unchecked")
123     Collection<Role> getRoles();
124 
125     /**
126      *
127      * @return an unmodifiable collection of registered statValues
128      */
129     Collection<StatValue> getValues();
130 
131     /**
132      * Reset all StatValues (don't remove them)
133      */
134     void reset();
135 
136     /**
137      * Identifier class for Monitors
138      */
139     public static class Key
140     {
141         public final static String DEFAULT = "default";
142 
143         private final String name;
144 
145         private final String category;
146 
147         private final String subsystem;
148 
149         public Key( String name, String category, String subsystem )
150         {
151             super();
152             if (name == null)
153             {
154                 throw new IllegalArgumentException( "A name must be provided" );
155             }
156             this.name = name;
157             this.category = category != null ? category : DEFAULT;
158             this.subsystem = subsystem != null ? subsystem : DEFAULT;;
159         }
160 
161         @Override
162         public String toString()
163         {
164             StringBuffer stb = new StringBuffer();
165             stb.append( "name=" );
166             stb.append( name );
167             if ( category != null )
168             {
169                 stb.append( "\ncategory=" );
170                 stb.append( category );
171             }
172             if ( subsystem != null )
173             {
174                 stb.append( "\nsubsystem=" );
175                 stb.append( subsystem );
176             }
177             return stb.toString();
178         }
179 
180         @Override
181         public int hashCode()
182         {
183             final int prime = 31;
184             int result = 1;
185             result = prime * result + ( ( category == null ) ? 0 : category.hashCode() );
186             result = prime * result + ( ( name == null ) ? 0 : name.hashCode() );
187             result = prime * result + ( ( subsystem == null ) ? 0 : subsystem.hashCode() );
188             return result;
189         }
190 
191         @Override
192         public boolean equals( Object obj )
193         {
194             if ( this == obj )
195             {
196                 return true;
197             }
198             if ( obj == null )
199             {
200                 return false;
201             }
202             if ( getClass() != obj.getClass() )
203             {
204                 return false;
205             }
206             final Key other = (Key) obj;
207             if ( category == null )
208             {
209                 if ( other.category != null )
210                 {
211                     return false;
212                 }
213             }
214             else if ( !category.equals( other.category ) )
215             {
216                 return false;
217             }
218             if ( name == null )
219             {
220                 if ( other.name != null )
221                 {
222                     return false;
223                 }
224             }
225             else if ( !name.equals( other.name ) )
226             {
227                 return false;
228             }
229             if ( subsystem == null )
230             {
231                 if ( other.subsystem != null )
232                 {
233                     return false;
234                 }
235             }
236             else if ( !subsystem.equals( other.subsystem ) )
237             {
238                 return false;
239             }
240             return true;
241         }
242 
243         public String getName()
244         {
245             return name;
246         }
247 
248         public String getCategory()
249         {
250             return category;
251         }
252 
253         public String getSubsystem()
254         {
255             return subsystem;
256         }
257 
258     }
259 
260 
261     /**
262      * Listener interface to get notified on montor events
263      */
264     public static interface Listener
265     {
266         void onStatValueRegistered( StatValue value );
267     }
268 
269     /**
270      * Monitor that accepts Listeners and notify them on monitor events
271      */
272     public static interface Observable extends Monitor
273     {
274         /**
275          * @param listener listener to get registered
276          */
277         void addListener( Listener listener );
278 
279         /**
280          * @param listener listener to get removed
281          */
282         void removeListener( Listener listener );
283     }
284 }