KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > excalibur > instrument > manager > InstrumentProxy


1 /*
2
3  ============================================================================
4                    The Apache Software License, Version 1.1
5  ============================================================================
6  
7  Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
8  
9  Redistribution and use in source and binary forms, with or without modifica-
10  tion, are permitted provided that the following conditions are met:
11  
12  1. Redistributions of source code must retain the above copyright notice,
13     this list of conditions and the following disclaimer.
14  
15  2. Redistributions in binary form must reproduce the above copyright notice,
16     this list of conditions and the following disclaimer in the documentation
17     and/or other materials provided with the distribution.
18  
19  3. The end-user documentation included with the redistribution, if any, must
20     include the following acknowledgment: "This product includes software
21     developed by the Apache Software Foundation (http://www.apache.org/)."
22     Alternately, this acknowledgment may appear in the software itself, if
23     and wherever such third-party acknowledgments normally appear.
24  
25  4. The names "Jakarta", "Avalon", "Excalibur" and "Apache Software Foundation"
26     must not be used to endorse or promote products derived from this software
27     without prior written permission. For written permission, please contact
28     apache@apache.org.
29  
30  5. Products derived from this software may not be called "Apache", nor may
31     "Apache" appear in their name, without prior written permission of the
32     Apache Software Foundation.
33  
34  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
35  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
36  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
37  APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
38  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
39  DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
40  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
41  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
43  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44  
45  This software consists of voluntary contributions made by many individuals
46  on behalf of the Apache Software Foundation. For more information on the
47  Apache Software Foundation, please see <http://www.apache.org/>.
48  
49 */

50 package org.apache.excalibur.instrument.manager;
51
52 import java.util.Arrays JavaDoc;
53 import java.util.Comparator JavaDoc;
54 import java.util.HashMap JavaDoc;
55
56 import org.apache.avalon.framework.configuration.Configurable;
57 import org.apache.avalon.framework.configuration.Configuration;
58 import org.apache.avalon.framework.configuration.ConfigurationException;
59 import org.apache.avalon.framework.configuration.DefaultConfiguration;
60 import org.apache.avalon.framework.logger.AbstractLogEnabled;
61 import org.apache.avalon.framework.logger.Logger;
62 import org.apache.excalibur.instrument.manager.interfaces.InstrumentManagerClient;
63 import org.apache.excalibur.instrument.manager.interfaces.InstrumentSampleUtils;
64
65 /**
66  * Instrumentables which do not implement ThreadSafe may have multiple instances
67  * created by the ComponentLocator. Each of these Instruments will share
68  * a common key and are profiled as a group. The InstrumentProxy is used
69  * make it easy for the InstrumentManager to control groups of Instruments
70  * as one.
71  * <p>
72  * The type of a Instrument can not be determined at configuration time.
73  * It is resolved when the Instrumentable actually registers the Instrument.
74  *
75  * @author <a HREF="mailto:leif@tanukisoftware.com">Leif Mortenson</a>
76  * @version CVS $Revision: 1.6 $ $Date: 2003/02/25 16:28:16 $
77  * @since 4.1
78  */

79 public class InstrumentProxy
80     extends AbstractLogEnabled
81     implements org.apache.excalibur.instrument.InstrumentProxy, Configurable
82 {
83     /** The InstrumentableProxy which owns the InstrumentProxy. */
84     private InstrumentableProxy m_instrumentableProxy;
85     
86     /** Configured flag. */
87     private boolean m_configured;
88     
89     /** Registered flag. */
90     private boolean m_registered;
91     
92     /** The name used to identify a Instrument. */
93     private String JavaDoc m_name;
94     
95     /** The description of the Instrumente. */
96     private String JavaDoc m_description;
97     
98     /** The Descriptor for the Instrument. */
99     private InstrumentDescriptorLocal m_descriptor;
100     
101     /** Type of the Instrument */
102     private int m_type;
103     
104     /** Array of registered Counter/ValueInstrumentListeners. */
105     private InstrumentListener[] m_listeners;
106     
107     /** Map of the maintained InstrumentSamples. */
108     private HashMap JavaDoc m_samples = new HashMap JavaDoc();
109     
110     /** Optimized array of the InstrumentSamples. */
111     private InstrumentSample[] m_sampleArray;
112     
113     /** Optimized array of the InstrumentSampleDescriptorLocals. */
114     private InstrumentSampleDescriptorLocal[] m_sampleDescriptorArray;
115     
116     /** Child logger to use for logging of new values. */
117     private Logger m_valueLogger;
118     
119     /** The most recent value set if this is a value instrument. */
120     private int m_lastValue;
121     
122     /** State Version. */
123     private int m_stateVersion;
124     
125     /*---------------------------------------------------------------
126      * Constructors
127      *-------------------------------------------------------------*/

128     /**
129      * Creates a new InstrumentProxy.
130      *
131      * @param instrumentableProxy The InstrumentableProxy which owns the
132      * InstrumentProxy.
133      * @param name The name used to identify a Instrumentable.
134      * @param description The description of the the Instrumentable.
135      */

136     InstrumentProxy( InstrumentableProxy instrumentableProxy,
137                      String JavaDoc name,
138                      String JavaDoc description )
139     {
140         m_instrumentableProxy = instrumentableProxy;
141         m_name = name;
142         m_description = description;
143         
144         // Create the descriptor
145
m_descriptor = new InstrumentDescriptorLocalImpl( this );
146     }
147     
148     /*---------------------------------------------------------------
149      * LogEnabled Methods
150      *-------------------------------------------------------------*/

151     public void enableLogging( Logger logger )
152     {
153         super.enableLogging( logger );
154         
155         // Create a child logger for logging setValue and increment calls so
156
// that they can be filtered out.
157
m_valueLogger = logger.getChildLogger( "values" );
158     }
159     
160     /*---------------------------------------------------------------
161      * Configurable Methods
162      *-------------------------------------------------------------*/

163     /**
164      * Configures the Instrument. Called from the InstrumentManager's
165      * configure method. The class does not need to be configured to
166      * function correctly.
167      *
168      * @param configuration Instrument configuration element from the
169      * InstrumentManager's configuration.
170      *
171      * @throws ConfigurationException If there are any configuration problems.
172      */

173     public void configure( Configuration configuration )
174         throws ConfigurationException
175     {
176         synchronized(this)
177         {
178             // The description is optional. Default to the description from the constructor.
179
m_description = configuration.getAttribute( "description", m_description );
180             
181             if ( getLogger().isDebugEnabled() )
182             {
183                 getLogger().debug( "Configuring Instrument: " + m_name + " as \"" +
184                     m_description + "\"" );
185             }
186             
187             m_configured = true;
188             
189             // Configure any Samples
190
Configuration[] sampleConfs = configuration.getChildren( "sample" );
191             for ( int i = 0; i < sampleConfs.length; i++ )
192             {
193                 Configuration sampleConf = sampleConfs[i];
194                 
195                 int sampleType = InstrumentSampleUtils.resolveInstrumentSampleType(
196                     sampleConf.getAttribute( "type" ) );
197                 long sampleInterval = sampleConf.getAttributeAsLong( "interval" );
198                 int sampleSize = sampleConf.getAttributeAsInteger( "size", 1 );
199                 
200                 // Build the sample name from its attributes. This makes it
201
// possible to avoid forcing the user to maintain a name as well.
202
String JavaDoc sampleName = InstrumentSampleUtils.generateFullInstrumentSampleName(
203                     m_name, sampleType, sampleInterval, sampleSize );
204                 
205                 String JavaDoc defaultDescription = InstrumentSampleUtils.generateInstrumentSampleName(
206                     sampleType, sampleInterval, sampleSize );
207                 String JavaDoc sampleDescription =
208                     sampleConf.getAttribute( "description", defaultDescription );
209                 
210                 if ( getLogger().isDebugEnabled() )
211                 {
212                     getLogger().debug( "Configuring InstrumentSample: " + sampleName +
213                         " as \"" + sampleDescription + "\"" );
214                 }
215                 
216                 AbstractInstrumentSample instrumentSample =
217                     (AbstractInstrumentSample)InstrumentSampleFactory.getInstrumentSample( this,
218                     sampleType, sampleName, sampleInterval, sampleSize, sampleDescription, 0 );
219                 instrumentSample.enableLogging( getLogger() );
220                 instrumentSample.setConfigured();
221                 
222                 addInstrumentSample( instrumentSample );
223             }
224         }
225     }
226     
227     /*---------------------------------------------------------------
228      * InstrumentProxy Methods
229      *-------------------------------------------------------------*/

230     /**
231      * Used by classes being profiles so that they can avoid unnecessary
232      * code when the data from a Instrument is not being used.
233      *
234      * @returns True if listeners are registered with the Instrument.
235      */

236     public boolean isActive() {
237         return m_listeners != null;
238     }
239     
240     /**
241      * Increments the Instrument by a specified count. This method should be
242      * optimized to be extremely light weight when there are no registered
243      * CounterInstrumentListeners.
244      *
245      * @param count A positive integer to increment the counter by.
246      */

247     public void increment( int count )
248     {
249         if ( m_type != InstrumentManagerClient.INSTRUMENT_TYPE_COUNTER )
250         {
251             // Type is not correct.
252
throw new IllegalStateException JavaDoc(
253                 "The proxy is not configured to handle CounterInstruments." );
254         }
255         
256         // Get a local reference to the listeners, so that synchronization can be avoided.
257
InstrumentListener[] listeners = m_listeners;
258         if ( listeners != null )
259         {
260             if ( m_valueLogger.isDebugEnabled() )
261             {
262                 m_valueLogger.debug( "increment() called for Instrument, " + m_name );
263             }
264             
265             long time = System.currentTimeMillis();
266             for ( int i = 0; i < listeners.length; i++ )
267             {
268                 CounterInstrumentListener listener =
269                     (CounterInstrumentListener)listeners[i];
270                 listener.increment( getName(), count, time );
271             }
272         }
273     }
274     
275     /**
276      * Sets the current value of the Instrument. This method is optimized
277      * to be extremely light weight when there are no registered
278      * ValueInstrumentListeners.
279      *
280      * @param value The new value for the Instrument.
281      */

282     public void setValue( int value )
283     {
284         if ( m_type != InstrumentManagerClient.INSTRUMENT_TYPE_VALUE )
285         {
286             // Type is not correct.
287
throw new IllegalStateException JavaDoc(
288                 "The proxy is not configured to handle ValueInstruments." );
289         }
290         
291         // Store the most recent value so that new listeners can be informed
292
// of the current value when they register. ints are single memory
293
// locations, so synchronization is not needed here.
294
m_lastValue = value;
295         
296         // Get a local reference to the listeners, so that synchronization can be avoided.
297
InstrumentListener[] listeners = m_listeners;
298         if ( listeners != null )
299         {
300             if ( m_valueLogger.isDebugEnabled() )
301             {
302                 m_valueLogger.debug( "setValue( " + value + " ) called for Instrument, " + m_name );
303             }
304             
305             long time = System.currentTimeMillis();
306             for ( int i = 0; i < listeners.length; i++ )
307             {
308                 ValueInstrumentListener listener =
309                     (ValueInstrumentListener)listeners[i];
310                 listener.setValue( getName(), value, time );
311             }
312         }
313     }
314     
315     /*---------------------------------------------------------------
316      * Methods
317      *-------------------------------------------------------------*/

318     /**
319      * Returns the InstrumentableProxy which owns the InstrumentProxy.
320      *
321      * @return The InstrumentableProxy which owns the InstrumentProxy.
322      */

323     InstrumentableProxy getInstrumentableProxy()
324     {
325         return m_instrumentableProxy;
326     }
327     
328     /**
329      * Returns true if the Instrument was configured in the instrumentables
330      * section of the configuration.
331      *
332      * @return True if configured.
333      */

334     boolean isConfigured()
335     {
336         return m_configured;
337     }
338
339     /**
340      * Returns true if the Instrument was registered with the Instrument
341      * Manager.
342      *
343      * @return True if registered.
344      */

345     boolean isRegistered()
346     {
347         return m_registered;
348     }
349     
350     /**
351      * Called by the InstrumentManager whenever an Instrument assigned to
352      * this proxy is registered.
353      */

354     void setRegistered()
355     {
356         m_registered = true;
357     }
358     
359     /**
360      * Gets the name for the Instrument. The Instrument Name is used to
361      * uniquely identify the Instrument during the configuration of the
362      * Profiler and to gain access to a InstrumentDescriptor through a
363      * InstrumentManager.
364      *
365      * @return The name used to identify a Instrumentable.
366      */

367     String JavaDoc getName()
368     {
369         return m_name;
370     }
371     
372     /**
373      * Sets the description for the Instrument. This description will
374      * be set during the configuration of the profiler if a configuration
375      * exists for this Instrument.
376      *
377      * @param description The description of the Instrument.
378      */

379     void setDescription( String JavaDoc description )
380     {
381         m_description = description;
382     }
383     
384     /**
385      * Gets the description of the Instrument.
386      *
387      * @return The description of the Instrument.
388      */

389     String JavaDoc getDescription()
390     {
391         return m_description;
392     }
393     
394     /**
395      * Returns a Descriptor for the Instrument.
396      *
397      * @return A Descriptor for the Instrument.
398      */

399     InstrumentDescriptorLocal getDescriptor()
400     {
401         return m_descriptor;
402     }
403     
404     /**
405      * Set the type of the Instrument. Once set, the type can not be changed.
406      *
407      * @param type Type of the Instrument.
408      */

409     void setType( int type )
410     {
411         synchronized(this)
412         {
413             if ( m_type != InstrumentManagerClient.INSTRUMENT_TYPE_NONE )
414             {
415                 throw new IllegalStateException JavaDoc( "Type already set." );
416             }
417             switch ( type )
418             {
419             case InstrumentManagerClient.INSTRUMENT_TYPE_COUNTER:
420             case InstrumentManagerClient.INSTRUMENT_TYPE_VALUE:
421                 m_type = type;
422                 break;
423             default:
424                 throw new IllegalStateException JavaDoc( type + " is not a valid type." );
425             }
426         }
427     }
428     
429     /**
430      * Returns the type of the Instrument.
431      *
432      * @return The type of the Instrument.
433      */

434     int getType()
435     {
436         return m_type;
437     }
438     
439     /**
440      * Adds a CounterInstrumentListener to the list of listeners which will
441      * receive updates of the value of the Instrument.
442      *
443      * @param listener CounterInstrumentListener which will start receiving
444      * profile updates.
445      *
446      * @throws IllegalStateException If the Instrument's type is not
447      * InstrumentManager.INSTRUMENT_TYPE_COUNTER.
448      */

449     void addCounterInstrumentListener( CounterInstrumentListener listener )
450     {
451         if ( m_type != InstrumentManagerClient.INSTRUMENT_TYPE_COUNTER )
452         {
453             // Type is not correct.
454
throw new IllegalStateException JavaDoc(
455                 "The proxy is not configured to handle CounterInstruments." );
456         }
457         
458         if ( getLogger().isDebugEnabled() )
459         {
460             getLogger().debug( "A CounterInstrumentListener was added to Instrument, " +
461                 m_name + " : " + listener.getClass().getName() );
462         }
463         
464         addInstrumentListener( listener );
465     }
466     
467     /**
468      * Removes a InstrumentListener from the list of listeners which will
469      * receive profile events.
470      *
471      * @param listener InstrumentListener which will stop receiving profile
472      * events.
473      *
474      * @throws IllegalStateException If the Instrument's type is not
475      * InstrumentManager.INSTRUMENT_TYPE_COUNTER.
476      */

477     void removeCounterInstrumentListener( CounterInstrumentListener listener )
478     {
479         if ( m_type != InstrumentManagerClient.INSTRUMENT_TYPE_COUNTER )
480         {
481             // Type is not correct.
482
throw new IllegalStateException JavaDoc(
483                 "The proxy is not configured to handle CounterInstruments." );
484         }
485         
486         if ( getLogger().isDebugEnabled() )
487         {
488             getLogger().debug( "A CounterInstrumentListener was removed from Instrument, " +
489                 m_name + " : " + listener.getClass().getName() );
490         }
491         
492         removeInstrumentListener( listener );
493     }
494     
495     /**
496      * Adds a ValueInstrumentListener to the list of listeners which will
497      * receive updates of the value of the Instrument.
498      *
499      * @param listener ValueInstrumentListener which will start receiving
500      * profile updates.
501      *
502      * @throws IllegalStateException If the Instrument's type is not
503      * InstrumentManager.INSTRUMENT_TYPE_VALUE.
504      */

505     void addValueInstrumentListener( ValueInstrumentListener listener )
506     {
507         if ( m_type != InstrumentManagerClient.INSTRUMENT_TYPE_VALUE )
508         {
509             // Type is not correct.
510
throw new IllegalStateException JavaDoc(
511                 "The proxy is not configured to handle ValueInstruments." );
512         }
513         
514         if ( getLogger().isDebugEnabled() )
515         {
516             getLogger().debug( "A ValueInstrumentListener was added to Instrument, " + m_name +
517                 " : " + listener.getClass().getName() );
518         }
519         
520         addInstrumentListener( listener );
521         
522         // Inform the new listener of the current value
523
long time = System.currentTimeMillis();
524         listener.setValue( getName(), m_lastValue, time );
525     }
526     
527     /**
528      * Removes a InstrumentListener from the list of listeners which will
529      * receive profile events.
530      *
531      * @param listener InstrumentListener which will stop receiving profile
532      * events.
533      *
534      * @throws IllegalStateException If the Instrument's type is not
535      * InstrumentManager.INSTRUMENT_TYPE_VALUE.
536      */

537     void removeValueInstrumentListener( ValueInstrumentListener listener )
538     {
539         if ( m_type != InstrumentManagerClient.INSTRUMENT_TYPE_VALUE )
540         {
541             // Type is not correct.
542
throw new IllegalStateException JavaDoc(
543                 "The proxy is not configured to handle ValueInstruments." );
544         }
545         
546         if ( getLogger().isDebugEnabled() )
547         {
548             getLogger().debug( "A ValueInstrumentListener was removed from Instrument, " + m_name +
549                 " : " + listener.getClass().getName() );
550         }
551         
552         removeInstrumentListener( listener );
553     }
554     
555     /**
556      * Add a InstrumentSample to the Instrument.
557      *
558      * @param InstrumentSample InstrumentSample to be added.
559      */

560     private void addInstrumentSample( InstrumentSample instrumentSample )
561     {
562         synchronized(this)
563         {
564             // If the type has not been set, set it. If it has been set, make sure this sample has
565
// the same type.
566
if ( m_type == InstrumentManagerClient.INSTRUMENT_TYPE_NONE )
567             {
568                 setType( instrumentSample.getInstrumentType() );
569             }
570             else if ( m_type != instrumentSample.getInstrumentType() )
571             {
572                 // The type is different.
573
throw new IllegalStateException JavaDoc( "The sample '" + instrumentSample.getName() +
574                     "' had its type set to " + getTypeName( m_type ) +
575                     " by another sample. This sample has a type of " +
576                     getTypeName( instrumentSample.getInstrumentType() ) + " and is not compatible." );
577             }
578             
579             // Make sure that a sample with the same name has not already been set.
580
String JavaDoc sampleName = instrumentSample.getName();
581             if ( m_samples.get( sampleName ) != null )
582             {
583                 throw new IllegalStateException JavaDoc( "More than one sample with the same name, '" +
584                     sampleName + "', can not be configured." );
585             }
586         
587             // Sample is safe to add.
588
m_samples.put( sampleName, instrumentSample );
589             
590             // Clear the optimized arrays
591
m_sampleArray = null;
592             m_sampleDescriptorArray = null;
593             
594             // Add the sample as a listener for this Instrument.
595
switch ( m_type )
596             {
597             case InstrumentManagerClient.INSTRUMENT_TYPE_COUNTER:
598                 addCounterInstrumentListener( (CounterInstrumentSample)instrumentSample );
599                 break;
600                 
601             case InstrumentManagerClient.INSTRUMENT_TYPE_VALUE:
602                 addValueInstrumentListener( (AbstractValueInstrumentSample)instrumentSample );
603                 break;
604                 
605             default:
606                 throw new IllegalStateException JavaDoc(
607                     "Don't know how to deal with the type: " + m_type );
608             }
609         }
610         
611         stateChanged();
612     }
613
614     /**
615      * Removes an InstrumentSample from the Instrument.
616      *
617      * @param InstrumentSample InstrumentSample to be removed.
618      */

619     void removeInstrumentSample( InstrumentSample instrumentSample )
620     {
621         synchronized(this)
622         {
623             // Remove the sample from the listener list for this Instrument.
624
switch ( m_type )
625             {
626             case InstrumentManagerClient.INSTRUMENT_TYPE_COUNTER:
627                 removeCounterInstrumentListener( (CounterInstrumentSample)instrumentSample );
628                 break;
629                 
630             case InstrumentManagerClient.INSTRUMENT_TYPE_VALUE:
631                 removeValueInstrumentListener( (AbstractValueInstrumentSample)instrumentSample );
632                 break;
633                 
634             default:
635                 throw new IllegalStateException JavaDoc(
636                     "Don't know how to deal with the type: " + m_type );
637             }
638             
639             // Remove the sample.
640
m_samples.remove( instrumentSample.getName() );
641             
642             // Clear the optimized arrays
643
m_sampleArray = null;
644             m_sampleDescriptorArray = null;
645         }
646         
647         stateChanged();
648     }
649     
650     /**
651      * Returns a InstrumentSample based on its name.
652      *
653      * @param InstrumentSampleName Name of the InstrumentSample being requested.
654      *
655      * @return The requested InstrumentSample or null if does not exist.
656      */

657     InstrumentSample getInstrumentSample( String JavaDoc InstrumentSampleName )
658     {
659         synchronized(this)
660         {
661             return (InstrumentSample)m_samples.get( InstrumentSampleName );
662         }
663     }
664     
665     /**
666      * Returns an array of the InstrumentSamples in the Instrument.
667      *
668      * @return An array of the InstrumentSamples in the Instrument.
669      */

670     InstrumentSample[] getInstrumentSamples()
671     {
672         InstrumentSample[] samples = m_sampleArray;
673         if ( samples == null )
674         {
675             samples = updateInstrumentSampleArray();
676         }
677         return samples;
678     }
679     
680     /**
681      * Returns a InstrumentSampleDescriptorLocal based on its name. If the
682      * requested sample is invalid in any way, then an expired Descriptor
683      * will be returned.
684      *
685      * @param sampleDescription Description to assign to the new Sample.
686      * @param sampleInterval Sample interval to use in the new Sample.
687      * @param sampleLease Requested lease time for the new Sample in
688      * milliseconds. The InstrumentManager may grant a
689      * lease which is shorter or longer than the requested
690      * period.
691      * @param sampleType Type of sample to request. Must be one of the
692      * following: InstrumentManagerClient.INSTRUMENT_SAMPLE_TYPE_COUNTER,
693      * InstrumentManagerClient.INSTRUMENT_SAMPLE_TYPE_MINIMUM,
694      * InstrumentManagerClient.INSTRUMENT_SAMPLE_TYPE_MAXIMUM,
695      * InstrumentManagerClient.INSTRUMENT_SAMPLE_TYPE_MEAN.
696      *
697      * @return The requested InstrumentSample.
698      *
699      * @throws NoSuchInstrumentSampleException If the specified InstrumentSample
700      * does not exist.
701      */

702     InstrumentSample createInstrumentSample( String JavaDoc sampleDescription,
703                                              long sampleInterval,
704                                              int sampleSize,
705                                              long sampleLease,
706                                              int sampleType )
707     {
708         getLogger().debug("Create new sample for " + m_name + ": interval=" + sampleInterval +
709             ", size=" + sampleSize + ", lease=" + sampleLease + ", type=" +
710             InstrumentSampleUtils.getInstrumentSampleTypeName( sampleType ) );
711         
712         // Validate the parameters
713
long now = System.currentTimeMillis();
714         
715         // Generate a name for the new sample
716
String JavaDoc sampleName = InstrumentSampleUtils.generateFullInstrumentSampleName(
717             m_name, sampleType, sampleInterval, sampleSize );
718         
719         InstrumentSample instrumentSample;
720         synchronized( this )
721         {
722             // It is possible that the requested sample already exists.
723
instrumentSample = getInstrumentSample( sampleName );
724             if ( instrumentSample != null )
725             {
726                 // The requested sample already exists.
727
instrumentSample.extendLease( sampleLease );
728             }
729             else
730             {
731                 // The new sample needs to be created.
732
instrumentSample = InstrumentSampleFactory.getInstrumentSample(
733                     this, sampleType, sampleName, sampleInterval, sampleSize,
734                     sampleDescription, sampleLease );
735                 instrumentSample.enableLogging( getLogger() );
736                 
737                 addInstrumentSample( instrumentSample );
738                 
739                 // Register the new sample with the InstrumentManager
740
getInstrumentableProxy().getInstrumentManager().
741                     registerLeasedInstrumentSample( instrumentSample );
742             }
743         }
744         
745         return instrumentSample;
746     }
747     
748     /**
749      * Returns an array of Descriptors for the InstrumentSamples in the
750      * Instrument.
751      *
752      * @return An array of Descriptors for the InstrumentSamples in the
753      * Instrument.
754      */

755     InstrumentSampleDescriptorLocal[] getInstrumentSampleDescriptors()
756     {
757         InstrumentSampleDescriptorLocal[] descriptors = m_sampleDescriptorArray;
758         if ( descriptors == null )
759         {
760             descriptors = updateInstrumentSampleDescriptorArray();
761         }
762         return descriptors;
763     }
764     
765     /**
766      * Returns the stateVersion of the instrument. The state version will be
767      * incremented each time any of the configuration of the instrument or
768      * any of its children is modified.
769      * Clients can use this value to tell whether or not anything has
770      * changed without having to do an exhaustive comparison.
771      *
772      * @return The state version of the instrument.
773      */

774     int getStateVersion()
775     {
776         return m_stateVersion;
777     }
778     
779     /**
780      * Common code to add a listener to the list of listeners which will
781      * receive updates of the value of the Instrument.
782      *
783      * @param listener InstrumentListener which will start receiving
784      * profile updates.
785      */

786     private void addInstrumentListener( InstrumentListener listener )
787     {
788         synchronized(this)
789         {
790             // Store the listeners in an array. This makes it possible to
791
// avoid synchronization while propagating events. Never change
792
// the contents of the listener array once it has been set to the
793
// m_listeners field.
794
InstrumentListener[] oldListeners = m_listeners;
795             InstrumentListener[] newListeners;
796             if ( oldListeners == null )
797             {
798                 newListeners = new InstrumentListener[] { listener };
799             }
800             else
801             {
802                 newListeners = new InstrumentListener[ oldListeners.length + 1 ];
803                 System.arraycopy( oldListeners, 0, newListeners, 0, oldListeners.length );
804                 newListeners[ oldListeners.length ] = listener;
805             }
806             
807             // Update the m_listeners field.
808
m_listeners = newListeners;
809         }
810     }
811     
812     /**
813      * Common code to remove a listener from the list of listeners which will
814      * receive updates of the value of the Instrument.
815      *
816      * @param listener InstrumentListener which will stop receiving
817      * profile updates.
818      */

819     private void removeInstrumentListener( InstrumentListener listener )
820     {
821         synchronized(this)
822         {
823             // Store the listeners in an array. This makes it possible to
824
// avoid synchronization while propagating events. Never change
825
// the contents of the listener array once it has been set to the
826
// m_listeners field.
827
InstrumentListener[] oldListeners = m_listeners;
828             InstrumentListener[] newListeners;
829             if ( oldListeners == null )
830             {
831                 // Means that this method should not have been called, but
832
// don't throw an error.
833
newListeners = null;
834             }
835             else if ( oldListeners.length == 1 )
836             {
837                 if ( oldListeners[0] == listener )
838                 {
839                     newListeners = null;
840                 }
841                 else
842                 {
843                     // The listener was not in the list.
844
newListeners = oldListeners;
845                 }
846             }
847             else
848             {
849                 // Look for the listener in the array.
850
int pos = -1;
851                 for ( int i = 0; i < oldListeners.length; i++ )
852                 {
853                     if ( oldListeners[i] == listener )
854                     {
855                         pos = i;
856                         break;
857                     }
858                 }
859                 
860                 if ( pos < 0 )
861                 {
862                     // The listener was not in the list.
863
newListeners = oldListeners;
864                 }
865                 else
866                 {
867                     newListeners = new InstrumentListener[ oldListeners.length - 1 ];
868                     if ( pos > 0 )
869                     {
870                         // Copy the head of the array
871
System.arraycopy( oldListeners, 0, newListeners, 0, pos );
872                     }
873                     if ( pos < oldListeners.length - 1 )
874                     {
875                         // Copy the tail of the array
876
System.arraycopy( oldListeners, pos + 1,
877                             newListeners, pos, oldListeners.length - 1 - pos );
878                     }
879                 }
880             }
881             
882             // Update the m_listeners field.
883
m_listeners = newListeners;
884         }
885     }
886     
887     /**
888      * Updates the cached array of InstrumentSamples taking synchronization into
889      * account.
890      *
891      * @return An array of the InstrumentSamples.
892      */

893     private InstrumentSample[] updateInstrumentSampleArray()
894     {
895         synchronized(this)
896         {
897             m_sampleArray = new InstrumentSample[ m_samples.size() ];
898             m_samples.values().toArray( m_sampleArray );
899             
900             // Sort the array. This is not a performance problem because this
901
// method is rarely called and doing it here saves cycles in the
902
// client.
903
Arrays.sort( m_sampleArray, new Comparator JavaDoc()
904                 {
905                     public int compare( Object JavaDoc o1, Object JavaDoc o2 )
906                     {
907                         return ((InstrumentSample)o1).getDescription().
908                             compareTo( ((InstrumentSample)o2).getDescription() );
909                     }
910                     
911                     public boolean equals( Object JavaDoc obj )
912                     {
913                         return false;
914                     }
915                 } );
916             
917             return m_sampleArray;
918         }
919     }
920     
921     /**
922      * Updates the cached array of InstrumentSampleDescriptorLocals taking
923      * synchronization into account.
924      *
925      * @return An array of the InstrumentSampleDescriptors.
926      */

927     private InstrumentSampleDescriptorLocal[] updateInstrumentSampleDescriptorArray()
928     {
929         synchronized(this)
930         {
931             if ( m_sampleArray == null )
932             {
933                 updateInstrumentSampleArray();
934             }
935             
936             m_sampleDescriptorArray =
937                 new InstrumentSampleDescriptorLocal[ m_sampleArray.length ];
938             for ( int i = 0; i < m_sampleArray.length; i++ )
939             {
940                 m_sampleDescriptorArray[i] = m_sampleArray[i].getDescriptor();
941             }
942             
943             return m_sampleDescriptorArray;
944         }
945     }
946     
947     /**
948      * Saves the current state into a Configuration.
949      *
950      * @return The state as a Configuration. Returns null if the configuration
951      * would not contain any information.
952      */

953     Configuration saveState()
954     {
955         boolean empty = true;
956         DefaultConfiguration state = new DefaultConfiguration( "instrument", "-" );
957         state.setAttribute( "name", m_name );
958         
959         InstrumentSample[] samples = getInstrumentSamples();
960         for ( int i = 0; i < samples.length; i++ )
961         {
962             Configuration childState = samples[i].saveState();
963             if ( childState != null )
964             {
965                 state.addChild( childState );
966                 empty = false;
967             }
968         }
969         
970         // Only return a state if it contains information.
971
if ( empty )
972         {
973             state = null;
974         }
975         return state;
976     }
977     
978     /**
979      * Loads the state into the Instrument.
980      *
981      * @param state Configuration object to load state from.
982      *
983      * @throws ConfigurationException If there were any problems loading the
984      * state.
985      */

986     void loadState( Configuration state ) throws ConfigurationException
987     {
988         synchronized( this )
989         {
990             Configuration[] instrumentSampleConfs = state.getChildren( "sample" );
991             for ( int i = 0; i < instrumentSampleConfs.length; i++ )
992             {
993                 Configuration instrumentSampleConf = instrumentSampleConfs[i];
994                 
995                 int sampleType = InstrumentSampleUtils.resolveInstrumentSampleType(
996                     instrumentSampleConf.getAttribute( "type" ) );
997                 long sampleInterval = instrumentSampleConf.getAttributeAsLong( "interval" );
998                 int sampleSize = instrumentSampleConf.getAttributeAsInteger( "size", 1 );
999                 
1000                // Build the sample name from its attributes. This makes it
1001
// possible to avoid forcing the user to maintain a name as well.
1002
String JavaDoc fullSampleName = InstrumentSampleUtils.generateFullInstrumentSampleName(
1003                    m_name, sampleType, sampleInterval, sampleSize );
1004                InstrumentSample sample = getInstrumentSample( fullSampleName );
1005                if ( sample == null )
1006                {
1007                    // Sample does not exist, see if it is a leased sample.
1008
long leaseExpirationTime =
1009                        instrumentSampleConf.getAttributeAsLong( "lease-expiration", 0 );
1010                    if ( leaseExpirationTime > 0 )
1011                    {
1012                        
1013                        String JavaDoc sampleName = InstrumentSampleUtils.generateInstrumentSampleName(
1014                            sampleType, sampleInterval, sampleSize );
1015                        String JavaDoc sampleDescription =
1016                            instrumentSampleConf.getAttribute( "description", sampleName );
1017                        
1018                        AbstractInstrumentSample instrumentSample =
1019                            (AbstractInstrumentSample)InstrumentSampleFactory.getInstrumentSample(
1020                            this, sampleType, fullSampleName, sampleInterval, sampleSize,
1021                            sampleDescription, 0 );
1022                        instrumentSample.enableLogging( getLogger() );
1023                        instrumentSample.loadState( instrumentSampleConf );
1024                        addInstrumentSample( instrumentSample );
1025                    }
1026                    else
1027                    {
1028                        getLogger().warn( "InstrumentSample entry ignored while loading state " +
1029                            "because the sample does not exist: " + fullSampleName );
1030                    }
1031                }
1032                else
1033                {
1034                    sample.loadState( instrumentSampleConf );
1035                }
1036            }
1037        }
1038        
1039        stateChanged();
1040    }
1041    
1042    /**
1043     * Called whenever the state of the instrument is changed.
1044     */

1045    protected void stateChanged()
1046    {
1047        m_stateVersion++;
1048        
1049        // Propagate to the parent
1050
m_instrumentableProxy.stateChanged();
1051    }
1052    
1053    /**
1054     * Returns the name of a Instrument type.
1055     *
1056     * @param type Type whose name is wanted.
1057     *
1058     * @return The name of a Instrument type.
1059     */

1060    public static String JavaDoc getTypeName( int type )
1061    {
1062        switch ( type )
1063        {
1064        case InstrumentManagerClient.INSTRUMENT_TYPE_NONE:
1065            return "none";
1066        case InstrumentManagerClient.INSTRUMENT_TYPE_COUNTER:
1067            return "counter";
1068        case InstrumentManagerClient.INSTRUMENT_TYPE_VALUE:
1069            return "value";
1070        default:
1071            throw new IllegalArgumentException JavaDoc( type + " is not a known Instrument type." );
1072        }
1073    }
1074}
1075
Popular Tags