KickJava   Java API By Example, From Geeks To Geeks.

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


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
14  * implied.
15  *
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */

19
20 package org.apache.excalibur.instrument.manager.impl;
21
22 import java.io.PrintWriter JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.Comparator JavaDoc;
25 import java.util.HashMap JavaDoc;
26
27 import org.apache.avalon.framework.configuration.Configurable;
28 import org.apache.avalon.framework.configuration.Configuration;
29 import org.apache.avalon.framework.configuration.ConfigurationException;
30 import org.apache.avalon.framework.logger.AbstractLogEnabled;
31 import org.apache.avalon.framework.logger.Logger;
32
33 import org.apache.excalibur.instrument.manager.CounterInstrumentListener;
34 import org.apache.excalibur.instrument.manager.DefaultInstrumentManager;
35 import org.apache.excalibur.instrument.manager.InstrumentDescriptor;
36 import org.apache.excalibur.instrument.manager.InstrumentListener;
37 import org.apache.excalibur.instrument.manager.InstrumentSampleDescriptor;
38 import org.apache.excalibur.instrument.manager.InstrumentSampleUtils;
39 import org.apache.excalibur.instrument.manager.ValueInstrumentListener;
40
41 /**
42  * Instrumentables which do not implement ThreadSafe may have multiple instances
43  * created by the ComponentLocator. Each of these Instruments will share
44  * a common key and are instrumented as a group. The InstrumentProxy is used
45  * make it easy for the InstrumentManager to control groups of Instruments
46  * as one.
47  * <p>
48  * The type of a Instrument can not be determined at configuration time.
49  * It is resolved when the Instrumentable actually registers the Instrument.
50  *
51  * @author <a HREF="mailto:dev@avalon.apache.org">Avalon Development Team</a>
52  * @version CVS $Revision: 1.4 $ $Date: 2004/02/28 11:47:25 $
53  * @since 4.1
54  */

55 public class InstrumentProxy
56     extends AbstractLogEnabled
57     implements org.apache.excalibur.instrument.InstrumentProxy, Configurable
58 {
59     /** The InstrumentableProxy which owns the InstrumentProxy. */
60     private InstrumentableProxy m_instrumentableProxy;
61     
62     /** Configured flag. */
63     private boolean m_configured;
64     
65     /** Registered flag. */
66     private boolean m_registered;
67     
68     /** The name used to identify a Instrument. */
69     private String JavaDoc m_name;
70     
71     /** The description of the Instrumente. */
72     private String JavaDoc m_description;
73     
74     /** The Descriptor for the Instrument. */
75     private InstrumentDescriptor m_descriptor;
76     
77     /** Type of the Instrument */
78     private int m_type;
79     
80     /** Array of registered Counter/ValueInstrumentListeners. */
81     private InstrumentListener[] m_listeners;
82     
83     /** Map of the maintained InstrumentSamples. */
84     private HashMap JavaDoc m_samples = new HashMap JavaDoc();
85     
86     /** Optimized array of the InstrumentSamples. */
87     private InstrumentSample[] m_sampleArray;
88     
89     /** Optimized array of the InstrumentSampleDescriptors. */
90     private InstrumentSampleDescriptor[] m_sampleDescriptorArray;
91     
92     /** Child logger to use for logging of new values. */
93     private Logger m_valueLogger;
94     
95     /** The most recent value set if this is a value instrument. */
96     private int m_lastValue;
97     
98     /** State Version. */
99     private int m_stateVersion;
100     
101     /*---------------------------------------------------------------
102      * Constructors
103      *-------------------------------------------------------------*/

104     /**
105      * Creates a new InstrumentProxy.
106      *
107      * @param instrumentableProxy The InstrumentableProxy which owns the
108      * InstrumentProxy.
109      * @param name The name used to identify a Instrumentable.
110      * @param description The description of the the Instrumentable.
111      */

112     InstrumentProxy( InstrumentableProxy instrumentableProxy,
113                      String JavaDoc name,
114                      String JavaDoc description )
115     {
116         m_instrumentableProxy = instrumentableProxy;
117         m_name = name;
118         m_description = description;
119         
120         // Create the descriptor
121
m_descriptor = new InstrumentDescriptorImpl( this );
122     }
123     
124     /*---------------------------------------------------------------
125      * LogEnabled Methods
126      *-------------------------------------------------------------*/

127     public void enableLogging( Logger logger )
128     {
129         super.enableLogging( logger );
130         
131         // Create a child logger for logging setValue and increment calls so
132
// that they can be filtered out.
133
m_valueLogger = logger.getChildLogger( "values" );
134     }
135     
136     /*---------------------------------------------------------------
137      * Configurable Methods
138      *-------------------------------------------------------------*/

139     /**
140      * Configures the Instrument. Called from the InstrumentManager's
141      * configure method. The class does not need to be configured to
142      * function correctly.
143      *
144      * @param configuration Instrument configuration element from the
145      * InstrumentManager's configuration.
146      *
147      * @throws ConfigurationException If there are any configuration problems.
148      */

149     public void configure( Configuration configuration )
150         throws ConfigurationException
151     {
152         synchronized(this)
153         {
154             // The description is optional. Default to the description from the constructor.
155
m_description = configuration.getAttribute( "description", m_description );
156             
157             if ( getLogger().isDebugEnabled() )
158             {
159                 getLogger().debug( "Configuring Instrument: " + m_name + " as \"" +
160                     m_description + "\"" );
161             }
162             
163             m_configured = true;
164             
165             // Configure any Samples
166
Configuration[] sampleConfs = configuration.getChildren( "sample" );
167             for ( int i = 0; i < sampleConfs.length; i++ )
168             {
169                 Configuration sampleConf = sampleConfs[i];
170                 
171                 int sampleType = InstrumentSampleUtils.resolveInstrumentSampleType(
172                     sampleConf.getAttribute( "type" ) );
173                 long sampleInterval = sampleConf.getAttributeAsLong( "interval" );
174                 int sampleSize = sampleConf.getAttributeAsInteger( "size", 1 );
175                 
176                 // Build the sample name from its attributes. This makes it
177
// possible to avoid forcing the user to maintain a name as well.
178
String JavaDoc sampleName = InstrumentSampleUtils.generateFullInstrumentSampleName(
179                     m_name, sampleType, sampleInterval, sampleSize );
180                 
181                 String JavaDoc defaultDescription = InstrumentSampleUtils.generateInstrumentSampleName(
182                     sampleType, sampleInterval, sampleSize );
183                 String JavaDoc sampleDescription =
184                     sampleConf.getAttribute( "description", defaultDescription );
185                 
186                 if ( getLogger().isDebugEnabled() )
187                 {
188                     getLogger().debug( "Configuring InstrumentSample: " + sampleName +
189                         " as \"" + sampleDescription + "\"" );
190                 }
191                 
192                 // See if the sample already exists.
193
String JavaDoc fullSampleName = InstrumentSampleUtils.generateFullInstrumentSampleName(
194                     m_name, sampleType, sampleInterval, sampleSize );
195                 InstrumentSample sample = getInstrumentSample( fullSampleName );
196                 if ( sample == null )
197                 {
198                     AbstractInstrumentSample instrumentSample =
199                         (AbstractInstrumentSample)InstrumentSampleFactory.getInstrumentSample( this,
200                         sampleType, sampleName, sampleInterval, sampleSize, sampleDescription, 0 );
201                     instrumentSample.enableLogging( getLogger() );
202                     instrumentSample.setConfigured();
203                                 
204                     addInstrumentSample( instrumentSample );
205                 }
206                 else
207                 {
208                     // Sample already existed.
209
if ( sample instanceof AbstractInstrumentSample )
210                     {
211                         AbstractInstrumentSample instrumentSample =
212                             (AbstractInstrumentSample)sample;
213                         instrumentSample.setConfigured();
214                         // If the sample already existed we will need to make it permanent.
215
instrumentSample.makePermanent();
216                     }
217                     else
218                     {
219                         // Should never happen with normal operation but an error is better than
220
// silently failing.
221
getLogger().warn(
222                             "Instrument sample was configured but already existed and "
223                             + "could not be cast to an AbstractInstrumentSample. "
224                             + "Name: " + fullSampleName + ", Class: "
225                             + sample.getClass().getName() );
226                     }
227                 }
228             }
229         }
230     }
231     
232     /*---------------------------------------------------------------
233      * InstrumentProxy Methods
234      *-------------------------------------------------------------*/

235     /**
236      * Used by classes being instrumented so that they can avoid unnecessary
237      * code when the data from a Instrument is not being used.
238      *
239      * @returns True if listeners are registered with the Instrument.
240      */

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

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

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

323     /**
324      * Returns the InstrumentableProxy which owns the InstrumentProxy.
325      *
326      * @return The InstrumentableProxy which owns the InstrumentProxy.
327      */

328     InstrumentableProxy getInstrumentableProxy()
329     {
330         return m_instrumentableProxy;
331     }
332     
333     /**
334      * Returns true if the Instrument was configured in the instrumentables
335      * section of the configuration.
336      *
337      * @return True if configured.
338      */

339     boolean isConfigured()
340     {
341         return m_configured;
342     }
343
344     /**
345      * Returns true if the Instrument was registered with the Instrument
346      * Manager.
347      *
348      * @return True if registered.
349      */

350     boolean isRegistered()
351     {
352         return m_registered;
353     }
354     
355     /**
356      * Called by the InstrumentManager whenever an Instrument assigned to
357      * this proxy is registered.
358      */

359     void setRegistered()
360     {
361         if ( !m_registered )
362         {
363             m_registered = true;
364             stateChanged();
365         }
366     }
367     
368     /**
369      * Gets the name for the Instrument. The Instrument Name is used to
370      * uniquely identify the Instrument during configuration and to gain
371      * access to a InstrumentDescriptor through an InstrumentManager.
372      *
373      * @return The name used to identify a Instrumentable.
374      */

375     String JavaDoc getName()
376     {
377         return m_name;
378     }
379     
380     /**
381      * Sets the description for the Instrument. This description will
382      * be set during configuration if a configuration exists for this
383      * Instrument.
384      *
385      * @param description The description of the Instrument.
386      */

387     void setDescription( String JavaDoc description )
388     {
389         String JavaDoc oldDescription = m_description; // thread safety.
390
if ( ( oldDescription == description ) || ( ( description != null ) && description.equals( oldDescription ) ) )
391         {
392             // No change
393
}
394         else
395         {
396             m_description = description;
397             stateChanged();
398         }
399     }
400     
401     /**
402      * Gets the description of the Instrument.
403      *
404      * @return The description of the Instrument.
405      */

406     String JavaDoc getDescription()
407     {
408         return m_description;
409     }
410     
411     /**
412      * Returns a Descriptor for the Instrument.
413      *
414      * @return A Descriptor for the Instrument.
415      */

416     InstrumentDescriptor getDescriptor()
417     {
418         return m_descriptor;
419     }
420     
421     /**
422      * Set the type of the Instrument. Once set, the type can not be changed.
423      *
424      * @param type Type of the Instrument.
425      */

426     void setType( int type )
427     {
428         synchronized(this)
429         {
430             if ( m_type != DefaultInstrumentManager.INSTRUMENT_TYPE_NONE )
431             {
432                 throw new IllegalStateException JavaDoc( "Type already set." );
433             }
434             switch ( type )
435             {
436             case DefaultInstrumentManager.INSTRUMENT_TYPE_COUNTER:
437             case DefaultInstrumentManager.INSTRUMENT_TYPE_VALUE:
438                 m_type = type;
439                 break;
440             default:
441                 throw new IllegalStateException JavaDoc( type + " is not a valid type." );
442             }
443         }
444     }
445     
446     /**
447      * Returns the type of the Instrument.
448      *
449      * @return The type of the Instrument.
450      */

451     int getType()
452     {
453         return m_type;
454     }
455     
456     /**
457      * Adds a CounterInstrumentListener to the list of listeners which will
458      * receive updates of the value of the Instrument.
459      *
460      * @param listener CounterInstrumentListener which will start receiving
461      * updates.
462      *
463      * @throws IllegalStateException If the Instrument's type is not
464      * InstrumentManager.INSTRUMENT_TYPE_COUNTER.
465      */

466     void addCounterInstrumentListener( CounterInstrumentListener listener )
467     {
468         if ( m_type != DefaultInstrumentManager.INSTRUMENT_TYPE_COUNTER )
469         {
470             // Type is not correct.
471
throw new IllegalStateException JavaDoc(
472                 "The proxy is not configured to handle CounterInstruments." );
473         }
474         
475         if ( getLogger().isDebugEnabled() )
476         {
477             getLogger().debug( "A CounterInstrumentListener was added to Instrument, " +
478                 m_name + " : " + listener.getClass().getName() );
479         }
480         
481         addInstrumentListener( listener );
482     }
483     
484     /**
485      * Removes a InstrumentListener from the list of listeners which will
486      * receive events.
487      *
488      * @param listener InstrumentListener which will stop receiving events.
489      *
490      * @throws IllegalStateException If the Instrument's type is not
491      * InstrumentManager.INSTRUMENT_TYPE_COUNTER.
492      */

493     void removeCounterInstrumentListener( CounterInstrumentListener listener )
494     {
495         if ( m_type != DefaultInstrumentManager.INSTRUMENT_TYPE_COUNTER )
496         {
497             // Type is not correct.
498
throw new IllegalStateException JavaDoc(
499                 "The proxy is not configured to handle CounterInstruments." );
500         }
501         
502         if ( getLogger().isDebugEnabled() )
503         {
504             getLogger().debug( "A CounterInstrumentListener was removed from Instrument, " +
505                 m_name + " : " + listener.getClass().getName() );
506         }
507         
508         removeInstrumentListener( listener );
509     }
510     
511     /**
512      * Adds a ValueInstrumentListener to the list of listeners which will
513      * receive updates of the value of the Instrument.
514      *
515      * @param listener ValueInstrumentListener which will start receiving
516      * updates.
517      *
518      * @throws IllegalStateException If the Instrument's type is not
519      * InstrumentManager.INSTRUMENT_TYPE_VALUE.
520      */

521     void addValueInstrumentListener( ValueInstrumentListener listener )
522     {
523         if ( m_type != DefaultInstrumentManager.INSTRUMENT_TYPE_VALUE )
524         {
525             // Type is not correct.
526
throw new IllegalStateException JavaDoc(
527                 "The proxy is not configured to handle ValueInstruments." );
528         }
529         
530         if ( getLogger().isDebugEnabled() )
531         {
532             getLogger().debug( "A ValueInstrumentListener was added to Instrument, " + m_name +
533                 " : " + listener.getClass().getName() );
534         }
535         
536         addInstrumentListener( listener );
537         
538         // Inform the new listener of the current value
539
long time = System.currentTimeMillis();
540         listener.setValue( getName(), m_lastValue, time );
541     }
542     
543     /**
544      * Removes a InstrumentListener from the list of listeners which will
545      * receive events.
546      *
547      * @param listener InstrumentListener which will stop receiving events.
548      *
549      * @throws IllegalStateException If the Instrument's type is not
550      * InstrumentManager.INSTRUMENT_TYPE_VALUE.
551      */

552     void removeValueInstrumentListener( ValueInstrumentListener listener )
553     {
554         if ( m_type != DefaultInstrumentManager.INSTRUMENT_TYPE_VALUE )
555         {
556             // Type is not correct.
557
throw new IllegalStateException JavaDoc(
558                 "The proxy is not configured to handle ValueInstruments." );
559         }
560         
561         if ( getLogger().isDebugEnabled() )
562         {
563             getLogger().debug( "A ValueInstrumentListener was removed from Instrument, " + m_name +
564                 " : " + listener.getClass().getName() );
565         }
566         
567         removeInstrumentListener( listener );
568     }
569     
570     /**
571      * Add a InstrumentSample to the Instrument.
572      *
573      * @param InstrumentSample InstrumentSample to be added.
574      */

575     private void addInstrumentSample( InstrumentSample instrumentSample )
576     {
577         synchronized(this)
578         {
579             // If the type has not been set, set it. If it has been set, make sure this sample has
580
// the same type.
581
if ( m_type == DefaultInstrumentManager.INSTRUMENT_TYPE_NONE )
582             {
583                 setType( instrumentSample.getInstrumentType() );
584             }
585             else if ( m_type != instrumentSample.getInstrumentType() )
586             {
587                 // The type is different.
588
throw new IllegalStateException JavaDoc( "The sample '" + instrumentSample.getName() +
589                     "' had its type set to " + getTypeName( m_type ) +
590                     " by another sample. This sample has a type of " +
591                     getTypeName( instrumentSample.getInstrumentType() ) + " and is not compatible." );
592             }
593             
594             // Make sure that a sample with the same name has not already been set.
595
String JavaDoc sampleName = instrumentSample.getName();
596             if ( m_samples.get( sampleName ) != null )
597             {
598                 throw new IllegalStateException JavaDoc( "More than one sample with the same name, '" +
599                     sampleName + "', can not be configured." );
600             }
601         
602             // Sample is safe to add.
603
m_samples.put( sampleName, instrumentSample );
604             
605             // Clear the optimized arrays
606
m_sampleArray = null;
607             m_sampleDescriptorArray = null;
608             
609             // Add the sample as a listener for this Instrument.
610
switch ( m_type )
611             {
612             case DefaultInstrumentManager.INSTRUMENT_TYPE_COUNTER:
613                 addCounterInstrumentListener( (CounterInstrumentSample)instrumentSample );
614                 break;
615                 
616             case DefaultInstrumentManager.INSTRUMENT_TYPE_VALUE:
617                 addValueInstrumentListener( (AbstractValueInstrumentSample)instrumentSample );
618                 break;
619                 
620             default:
621                 throw new IllegalStateException JavaDoc(
622                     "Don't know how to deal with the type: " + m_type );
623             }
624         }
625         
626         if ( instrumentSample.getLeaseExpirationTime() == 0 )
627         {
628             m_instrumentableProxy.getInstrumentManager().incrementPermanentSampleCount();
629         }
630         else
631         {
632             m_instrumentableProxy.getInstrumentManager().incrementLeasedSampleCount();
633         }
634         
635         stateChanged();
636     }
637
638     /**
639      * Removes an InstrumentSample from the Instrument.
640      *
641      * @param InstrumentSample InstrumentSample to be removed.
642      */

643     void removeInstrumentSample( InstrumentSample instrumentSample )
644     {
645         synchronized(this)
646         {
647             // Remove the sample from the listener list for this Instrument.
648
switch ( m_type )
649             {
650             case DefaultInstrumentManager.INSTRUMENT_TYPE_COUNTER:
651                 removeCounterInstrumentListener( (CounterInstrumentSample)instrumentSample );
652                 break;
653                 
654             case DefaultInstrumentManager.INSTRUMENT_TYPE_VALUE:
655                 removeValueInstrumentListener( (AbstractValueInstrumentSample)instrumentSample );
656                 break;
657                 
658             default:
659                 throw new IllegalStateException JavaDoc(
660                     "Don't know how to deal with the type: " + m_type );
661             }
662             
663             // Remove the sample.
664
m_samples.remove( instrumentSample.getName() );
665             
666             // Clear the optimized arrays
667
m_sampleArray = null;
668             m_sampleDescriptorArray = null;
669         }
670         
671         m_instrumentableProxy.getInstrumentManager().decrementLeasedSampleCount();
672         
673         stateChanged();
674     }
675     
676     /**
677      * Returns a InstrumentSample based on its name.
678      *
679      * @param instrumentSampleName Name of the InstrumentSample being requested.
680      *
681      * @return The requested InstrumentSample or null if does not exist.
682      */

683     InstrumentSample getInstrumentSample( String JavaDoc instrumentSampleName )
684     {
685         synchronized(this)
686         {
687             return (InstrumentSample)m_samples.get( instrumentSampleName );
688         }
689     }
690     
691     /**
692      * Returns an array of the InstrumentSamples in the Instrument.
693      *
694      * @return An array of the InstrumentSamples in the Instrument.
695      */

696     InstrumentSample[] getInstrumentSamples()
697     {
698         InstrumentSample[] samples = m_sampleArray;
699         if ( samples == null )
700         {
701             samples = updateInstrumentSampleArray();
702         }
703         return samples;
704     }
705     
706     /**
707      * Returns an InstrumentSampleDescriptor based on its name. If the
708      * requested sample is invalid in any way, then an expired Descriptor
709      * will be returned.
710      *
711      * @param sampleDescription Description to assign to the new Sample.
712      * @param sampleInterval Sample interval to use in the new Sample.
713      * @param sampleLease Requested lease time for the new Sample in
714      * milliseconds. The InstrumentManager may grant a
715      * lease which is shorter or longer than the requested
716      * period.
717      * @param sampleType Type of sample to request. Must be one of the
718      * following: DefaultInstrumentManager.INSTRUMENT_SAMPLE_TYPE_COUNTER,
719      * DefaultInstrumentManager.INSTRUMENT_SAMPLE_TYPE_MINIMUM,
720      * DefaultInstrumentManager.INSTRUMENT_SAMPLE_TYPE_MAXIMUM,
721      * DefaultInstrumentManager.INSTRUMENT_SAMPLE_TYPE_MEAN.
722      *
723      * @return The requested InstrumentSample.
724      *
725      * @throws NoSuchInstrumentSampleException If the specified InstrumentSample
726      * does not exist.
727      */

728     InstrumentSample createInstrumentSample( String JavaDoc sampleDescription,
729                                              long sampleInterval,
730                                              int sampleSize,
731                                              long sampleLease,
732                                              int sampleType )
733     {
734         if ( getLogger().isDebugEnabled() )
735         {
736             getLogger().debug( "Create new sample for " + m_name + ": interval=" + sampleInterval +
737                 ", size=" + sampleSize + ", lease=" + sampleLease + ", type=" +
738                 InstrumentSampleUtils.getInstrumentSampleTypeName( sampleType ) );
739         }
740         
741         DefaultInstrumentManagerImpl manager = m_instrumentableProxy.getInstrumentManager();
742         
743         // Make sure the sampleSize is valid.
744
sampleSize = Math.max( 1, Math.min( sampleSize, manager.getMaxLeasedSampleSize() ) );
745         
746         // Generate a name for the new sample
747
String JavaDoc sampleName = InstrumentSampleUtils.generateFullInstrumentSampleName(
748             m_name, sampleType, sampleInterval, sampleSize );
749         
750         InstrumentSample instrumentSample;
751         synchronized( this )
752         {
753             // It is possible that the requested sample already exists.
754
instrumentSample = getInstrumentSample( sampleName );
755             if ( instrumentSample != null )
756             {
757                 // The requested sample already exists.
758
instrumentSample.extendLease( sampleLease );
759             }
760             else
761             {
762                 // The new sample needs to be created.
763

764                 // Make sure the lease is valid.
765
boolean expired = false;
766                 sampleLease =
767                     Math.max( 1, Math.min( sampleLease, manager.getMaxLeasedSampleLease() ) );
768                 if ( ( manager.getLeaseSampleCount() >= manager.getMaxLeasedSamples() )
769                     || ( sampleLease == 1 ) )
770                 {
771                     // Unable to grant any more leases. We always need to return a lease
772
// object, but return one which expires immediately.
773
sampleLease = 1;
774                     expired = true;
775                 }
776                 
777                 instrumentSample = InstrumentSampleFactory.getInstrumentSample(
778                     this, sampleType, sampleName, sampleInterval, sampleSize,
779                     sampleDescription, sampleLease );
780                 instrumentSample.enableLogging( getLogger() );
781                 
782                 // Do not bother registering expired dummy leases.
783
if ( !expired )
784                 {
785                     m_instrumentableProxy.getInstrumentManager().incrementLeaseRequests();
786                     
787                     addInstrumentSample( instrumentSample );
788                     
789                     // Register the new sample with the InstrumentManager
790
getInstrumentableProxy().getInstrumentManager().
791                         registerLeasedInstrumentSample( instrumentSample );
792                 }
793             }
794         }
795         
796         return instrumentSample;
797     }
798     
799     /**
800      * Returns an array of Descriptors for the InstrumentSamples in the
801      * Instrument.
802      *
803      * @return An array of Descriptors for the InstrumentSamples in the
804      * Instrument.
805      */

806     InstrumentSampleDescriptor[] getInstrumentSampleDescriptors()
807     {
808         InstrumentSampleDescriptor[] descriptors = m_sampleDescriptorArray;
809         if ( descriptors == null )
810         {
811             descriptors = updateInstrumentSampleDescriptorArray();
812         }
813         return descriptors;
814     }
815     
816     /**
817      * Returns the stateVersion of the instrument. The state version will be
818      * incremented each time any of the configuration of the instrument or
819      * any of its children is modified.
820      * Clients can use this value to tell whether or not anything has
821      * changed without having to do an exhaustive comparison.
822      *
823      * @return The state version of the instrument.
824      */

825     int getStateVersion()
826     {
827         return m_stateVersion;
828     }
829     
830     /**
831      * Common code to add a listener to the list of listeners which will
832      * receive updates of the value of the Instrument.
833      *
834      * @param listener InstrumentListener which will start receiving
835      * updates.
836      */

837     private void addInstrumentListener( InstrumentListener listener )
838     {
839         synchronized(this)
840         {
841             // Store the listeners in an array. This makes it possible to
842
// avoid synchronization while propagating events. Never change
843
// the contents of the listener array once it has been set to the
844
// m_listeners field.
845
InstrumentListener[] oldListeners = m_listeners;
846             InstrumentListener[] newListeners;
847             if ( oldListeners == null )
848             {
849                 newListeners = new InstrumentListener[] { listener };
850             }
851             else
852             {
853                 newListeners = new InstrumentListener[ oldListeners.length + 1 ];
854                 System.arraycopy( oldListeners, 0, newListeners, 0, oldListeners.length );
855                 newListeners[ oldListeners.length ] = listener;
856             }
857             
858             // Update the m_listeners field.
859
m_listeners = newListeners;
860         }
861     }
862     
863     /**
864      * Common code to remove a listener from the list of listeners which will
865      * receive updates of the value of the Instrument.
866      *
867      * @param listener InstrumentListener which will stop receiving
868      * updates.
869      */

870     private void removeInstrumentListener( InstrumentListener listener )
871     {
872         synchronized(this)
873         {
874             // Store the listeners in an array. This makes it possible to
875
// avoid synchronization while propagating events. Never change
876
// the contents of the listener array once it has been set to the
877
// m_listeners field.
878
InstrumentListener[] oldListeners = m_listeners;
879             InstrumentListener[] newListeners;
880             if ( oldListeners == null )
881             {
882                 // Means that this method should not have been called, but
883
// don't throw an error.
884
newListeners = null;
885             }
886             else if ( oldListeners.length == 1 )
887             {
888                 if ( oldListeners[0] == listener )
889                 {
890                     newListeners = null;
891                 }
892                 else
893                 {
894                     // The listener was not in the list.
895
newListeners = oldListeners;
896                 }
897             }
898             else
899             {
900                 // Look for the listener in the array.
901
int pos = -1;
902                 for ( int i = 0; i < oldListeners.length; i++ )
903                 {
904                     if ( oldListeners[i] == listener )
905                     {
906                         pos = i;
907                         break;
908                     }
909                 }
910                 
911                 if ( pos < 0 )
912                 {
913                     // The listener was not in the list.
914
newListeners = oldListeners;
915                 }
916                 else
917                 {
918                     newListeners = new InstrumentListener[ oldListeners.length - 1 ];
919                     if ( pos > 0 )
920                     {
921                         // Copy the head of the array
922
System.arraycopy( oldListeners, 0, newListeners, 0, pos );
923                     }
924                     if ( pos < oldListeners.length - 1 )
925                     {
926                         // Copy the tail of the array
927
System.arraycopy( oldListeners, pos + 1,
928                             newListeners, pos, oldListeners.length - 1 - pos );
929                     }
930                 }
931             }
932             
933             // Update the m_listeners field.
934
m_listeners = newListeners;
935         }
936     }
937     
938     /**
939      * Updates the cached array of InstrumentSamples taking synchronization into
940      * account.
941      *
942      * @return An array of the InstrumentSamples.
943      */

944     private InstrumentSample[] updateInstrumentSampleArray()
945     {
946         synchronized(this)
947         {
948             InstrumentSample[] sampleArray = new InstrumentSample[ m_samples.size() ];
949             m_samples.values().toArray( sampleArray );
950             
951             // Sort the array. This is not a performance problem because this
952
// method is rarely called and doing it here saves cycles in the
953
// client.
954
Arrays.sort( sampleArray, new Comparator JavaDoc()
955                 {
956                     public int compare( Object JavaDoc o1, Object JavaDoc o2 )
957                     {
958                         return ((InstrumentSample)o1).getDescription().
959                             compareTo( ((InstrumentSample)o2).getDescription() );
960                     }
961                     
962                     public boolean equals( Object JavaDoc obj )
963                     {
964                         return false;
965                     }
966                 } );
967             
968             
969             // Once we are done modifying this array, set it to the variable accessable outside
970
// of synchronization.
971
m_sampleArray = sampleArray;
972             
973             return sampleArray;
974         }
975     }
976     
977     /**
978      * Updates the cached array of InstrumentSampleDescriptors taking
979      * synchronization into account.
980      *
981      * @return An array of the InstrumentSampleDescriptors.
982      */

983     private InstrumentSampleDescriptor[] updateInstrumentSampleDescriptorArray()
984     {
985         synchronized(this)
986         {
987             // Get the proxy array. This is done in synchronization so it is not possible that it
988
// will be reset before we obtain the descriptor array. They are both set to null
989
// at the same time when there is a change.
990
InstrumentSample[] sampleArray = m_sampleArray;
991             if ( sampleArray == null )
992             {
993                 sampleArray = updateInstrumentSampleArray();
994             }
995             
996             InstrumentSampleDescriptor[] sampleDescriptorArray =
997                 new InstrumentSampleDescriptor[ m_sampleArray.length ];
998             for ( int i = 0; i < sampleArray.length; i++ )
999             {
1000                sampleDescriptorArray[i] = sampleArray[i].getDescriptor();
1001            }
1002            
1003            // Once we are done modifying this array, set it to the variable accessable outside
1004
// of synchronization.
1005
m_sampleDescriptorArray = sampleDescriptorArray;
1006            
1007            return sampleDescriptorArray;
1008        }
1009    }
1010    
1011    /**
1012     * Writes the current state to a PrintWriter as XML.
1013     *
1014     * @param out The PrintWriter to which the state should be written.
1015     */

1016    void writeState( PrintWriter JavaDoc out )
1017    {
1018        // Samples are the only things written to the state, so all we need to do is drill down
1019
// to them.
1020

1021        // Write out the states of any samples.
1022
InstrumentSample[] samples = getInstrumentSamples();
1023        for ( int i = 0; i < samples.length; i++ )
1024        {
1025            samples[i].writeState( out );
1026        }
1027    }
1028    
1029    /**
1030     * Loads the state of an Instrument Sample. If the does not exist and the
1031     * sample is leased then it will be created.
1032     *
1033     * @param state Configuration object to load state from.
1034     *
1035     * @return The sample into which the state was loaded. If the sample
1036     * did not exist and was not created then null is returned.
1037     *
1038     * @throws ConfigurationException If there were any problems loading the
1039     * state.
1040     */

1041    InstrumentSample loadSampleState( Configuration state ) throws ConfigurationException
1042    {
1043        //getLogger().debug( "instrument loadSampleState() " + m_name + " to " + this );
1044
InstrumentSample sample;
1045        synchronized( this )
1046        {
1047            Configuration instrumentSampleConf = state;
1048            
1049            int sampleType = InstrumentSampleUtils.resolveInstrumentSampleType(
1050                instrumentSampleConf.getAttribute( "type" ) );
1051            long sampleInterval = instrumentSampleConf.getAttributeAsLong( "interval" );
1052            int sampleSize = instrumentSampleConf.getAttributeAsInteger( "size", 1 );
1053            
1054            // Build the sample name from its attributes. This makes it
1055
// possible to avoid forcing the user to maintain a name as well.
1056
String JavaDoc fullSampleName = InstrumentSampleUtils.generateFullInstrumentSampleName(
1057                m_name, sampleType, sampleInterval, sampleSize );
1058            sample = getInstrumentSample( fullSampleName );
1059            if ( sample == null )
1060            {
1061                // Sample does not exist, see if it is a leased sample.
1062
long leaseExpirationTime =
1063                    instrumentSampleConf.getAttributeAsLong( "lease-expiration", 0 );
1064                if ( leaseExpirationTime > 0 )
1065                {
1066                    
1067                    String JavaDoc sampleName = InstrumentSampleUtils.generateInstrumentSampleName(
1068                        sampleType, sampleInterval, sampleSize );
1069                    String JavaDoc sampleDescription =
1070                        instrumentSampleConf.getAttribute( "description", sampleName );
1071                    
1072                    // Create the sample with an expiration time of 1. This will be expired
1073
// but not permanent. It will be set with the correct
1074
// expiration time will be set when its state is loaded.
1075
AbstractInstrumentSample instrumentSample =
1076                        (AbstractInstrumentSample)InstrumentSampleFactory.getInstrumentSample(
1077                        this, sampleType, fullSampleName, sampleInterval, sampleSize,
1078                        sampleDescription, 1 );
1079                    instrumentSample.enableLogging( getLogger() );
1080                    instrumentSample.loadState( instrumentSampleConf );
1081                    
1082                    addInstrumentSample( instrumentSample );
1083                    
1084                    sample = instrumentSample;
1085                }
1086                else
1087                {
1088                    // Permantent sample which no longer exists.
1089
getLogger().info( "InstrumentSample entry ignored while loading state " +
1090                        "because the sample does not exist: " + fullSampleName );
1091                }
1092            }
1093            else
1094            {
1095                sample.loadState( instrumentSampleConf );
1096            }
1097        }
1098        
1099        // If the sample's state was changed then it will call stateChanged for the instrument
1100

1101        return sample;
1102    }
1103    
1104    /**
1105     * Called whenever the state of the instrument is changed.
1106     */

1107    protected void stateChanged()
1108    {
1109        m_stateVersion++;
1110        
1111        // Propagate to the parent
1112
m_instrumentableProxy.stateChanged();
1113    }
1114    
1115    /**
1116     * Returns the name of a Instrument type.
1117     *
1118     * @param type Type whose name is wanted.
1119     *
1120     * @return The name of a Instrument type.
1121     */

1122    public static String JavaDoc getTypeName( int type )
1123    {
1124        switch ( type )
1125        {
1126        case DefaultInstrumentManager.INSTRUMENT_TYPE_NONE:
1127            return "none";
1128        case DefaultInstrumentManager.INSTRUMENT_TYPE_COUNTER:
1129            return "counter";
1130        case DefaultInstrumentManager.INSTRUMENT_TYPE_VALUE:
1131            return "value";
1132        default:
1133            throw new IllegalArgumentException JavaDoc( type + " is not a known Instrument type." );
1134        }
1135    }
1136}
1137
Popular Tags