KickJava   Java API By Example, From Geeks To Geeks.

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


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.File JavaDoc;
23 import java.io.FileInputStream JavaDoc;
24 import java.io.FileOutputStream JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.OutputStream JavaDoc;
28 import java.io.OutputStreamWriter JavaDoc;
29 import java.io.PrintWriter JavaDoc;
30 import java.util.ArrayList JavaDoc;
31 import java.util.Arrays JavaDoc;
32 import java.util.Comparator JavaDoc;
33 import java.util.HashMap JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.List JavaDoc;
36 import java.util.Map JavaDoc;
37
38 import org.apache.avalon.framework.activity.Disposable;
39 import org.apache.avalon.framework.activity.Initializable;
40 import org.apache.avalon.framework.configuration.Configurable;
41 import org.apache.avalon.framework.configuration.Configuration;
42 import org.apache.avalon.framework.configuration.ConfigurationException;
43 import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
44 import org.apache.avalon.framework.container.ContainerUtil;
45 import org.apache.avalon.framework.logger.AbstractLogEnabled;
46 import org.apache.avalon.framework.logger.Logger;
47 import org.apache.avalon.framework.service.ServiceException;
48
49 import org.apache.excalibur.instrument.AbstractInstrument;
50 import org.apache.excalibur.instrument.CounterInstrument;
51 import org.apache.excalibur.instrument.Instrument;
52 import org.apache.excalibur.instrument.InstrumentManager;
53 import org.apache.excalibur.instrument.Instrumentable;
54 import org.apache.excalibur.instrument.ValueInstrument;
55
56 import org.apache.excalibur.instrument.manager.DefaultInstrumentManager;
57 import org.apache.excalibur.instrument.manager.DefaultInstrumentManagerConnector;
58 import org.apache.excalibur.instrument.manager.InstrumentableDescriptor;
59 import org.apache.excalibur.instrument.manager.InstrumentDescriptor;
60 import org.apache.excalibur.instrument.manager.InstrumentSampleDescriptor;
61 import org.apache.excalibur.instrument.manager.InstrumentSampleUtils;
62 import org.apache.excalibur.instrument.manager.NoSuchInstrumentException;
63 import org.apache.excalibur.instrument.manager.NoSuchInstrumentSampleException;
64 import org.apache.excalibur.instrument.manager.NoSuchInstrumentableException;
65
66 /**
67  *
68  * @author <a HREF="mailto:dev@avalon.apache.org">Avalon Development Team</a>
69  * @version CVS $Revision: 1.4 $ $Date: 2004/02/28 11:47:25 $
70  * @since 4.1
71  */

72 public class DefaultInstrumentManagerImpl
73     extends AbstractLogEnabled
74     implements Configurable, Initializable, Disposable, DefaultInstrumentManager,
75         Instrumentable, Runnable JavaDoc
76 {
77     /** The name used to identify this InstrumentManager. */
78     private String JavaDoc m_name;
79
80     /** The description of this InstrumentManager. */
81     private String JavaDoc m_description;
82     
83     /** The maximum number of leased samples which will be allowed. This is
84      * important to prevent denial of service attacks using connectors. */

85     private int m_maxLeasedSamples;
86     
87     /** The maximum size of a leased sample. This is important to prevent
88      * denial of service attacks using connectors. */

89     private int m_maxLeasedSampleSize;
90     
91     /** The maximum amount of time that a lease will be granted for. This is
92      * important to prevent denial of service attacks using connectors. */

93     private long m_maxLeasedSampleLease;
94     
95     /** List of configured connectors. */
96     private List JavaDoc m_connectors = new ArrayList JavaDoc();
97
98     /** State file. */
99     private File JavaDoc m_stateFile;
100
101     /** Save state interval. */
102     private long m_stateInterval;
103
104     /** Last time that the state was saved. */
105     private long m_lastStateSave;
106
107     /** Semaphore for actions which must be synchronized */
108     private Object JavaDoc m_semaphore = new Object JavaDoc();
109
110     /** HashMap of all of the registered InstrumentableProxies by their keys. */
111     private Map JavaDoc m_instrumentableProxies = new HashMap JavaDoc();
112
113     /** Optimized array of the InstrumentableProxies. */
114     private InstrumentableProxy[] m_instrumentableProxyArray;
115
116     /** Optimized array of the InstrumentableDescriptors. */
117     private InstrumentableDescriptor[] m_instrumentableDescriptorArray;
118
119     /** List of leased InstrumentSamples. */
120     private List JavaDoc m_leasedInstrumentSamples = new ArrayList JavaDoc();
121     
122     /** Optimized array of the leased InstrumentSamples. */
123     private InstrumentSample[] m_leasedInstrumentSampleArray;
124     
125     /** Logger dedicated to logging translations. */
126     private Logger m_translationLogger;
127     
128     /** Map of all registered translations. */
129     private Map JavaDoc m_nameTranslations = new HashMap JavaDoc();
130     
131     /** Optimized array of the registered translations. */
132     private String JavaDoc[][] m_nameTranslationArray;
133     
134     /**
135      * Thread used to keep the instruments published by the InstrumentManager
136      * up to date.
137      */

138     private Thread JavaDoc m_runner;
139
140     /** Instrumentable Name assigned to this Instrumentable */
141     private String JavaDoc m_instrumentableName = "instrument-manager";
142
143     /** Instrument used to profile the total memory. */
144     private ValueInstrument m_totalMemoryInstrument;
145
146     /** Instrument used to profile the free memory. */
147     private ValueInstrument m_freeMemoryInstrument;
148
149     /** Instrument used to profile the in use memory. */
150     private ValueInstrument m_memoryInstrument;
151
152     /** Instrument used to profile the active thread count of the JVM. */
153     private ValueInstrument m_activeThreadCountInstrument;
154     
155     /** Instrument to track the number of times registerInstrumentable is called. */
156     private CounterInstrument m_registrationsInstrument;
157
158     /** The Instrumentable count. */
159     private int m_instrumentableCount;
160     
161     /** Instrument used to track the number of Instrumentables in the system. */
162     private ValueInstrument m_instrumentablesInstrument;
163
164     /** The Instrument count. */
165     private int m_instrumentCount;
166
167     /** Instrument used to track the number of Instruments in the system. */
168     private ValueInstrument m_instrumentsInstrument;
169
170     /** The Permanent Instrument Sample count. */
171     private int m_permanentSampleCount;
172
173     /** The Leased Instrument Sample count. */
174     private int m_leasedSampleCount;
175
176     /** Instrument used to track the number of Instrument samples in the system. */
177     private ValueInstrument m_samplesInstrument;
178
179     /** Instrument used to track the number of Leased Instrument samples in the system. */
180     private ValueInstrument m_leasedSamplesInstrument;
181     
182     /** Instrument used to track the number of lease requests. */
183     private CounterInstrument m_leaseRequestsInstrument;
184     
185     /** Instrument used to track the number of state saves performed. */
186     private CounterInstrument m_stateSavesInstrument;
187     
188     /** Instrument used to track the time it takes to save the state. */
189     private ValueInstrument m_stateSaveTimeInstrument;
190     
191     /** State Version. */
192     private int m_stateVersion;
193
194     /*---------------------------------------------------------------
195      * Constructors
196      *-------------------------------------------------------------*/

197     /**
198      * Creates a new DefaultInstrumentManagerImpl.
199      *
200      * @param name The name used to identify this InstrumentManager. Should not
201      * contain any spaces or periods.
202      *
203      * @deprecated Name should be set in the instrument configuration file.
204      */

205     public DefaultInstrumentManagerImpl( String JavaDoc name )
206     {
207         this();
208     }
209     
210     /**
211      * Creates a new DefaultInstrumentManagerImpl.
212      */

213     public DefaultInstrumentManagerImpl()
214     {
215         // Initialize the Instrumentable elements.
216
m_totalMemoryInstrument = new ValueInstrument( "total-memory" );
217         m_freeMemoryInstrument = new ValueInstrument( "free-memory" );
218         m_memoryInstrument = new ValueInstrument( "memory" );
219         m_activeThreadCountInstrument = new ValueInstrument( "active-thread-count" );
220         m_registrationsInstrument = new CounterInstrument( "instrumentable-registrations" );
221         m_instrumentablesInstrument = new ValueInstrument( "instrumentables" );
222         m_instrumentsInstrument = new ValueInstrument( "instruments" );
223         m_samplesInstrument = new ValueInstrument( "samples" );
224         m_leasedSamplesInstrument = new ValueInstrument( "leased-samples" );
225         m_leaseRequestsInstrument = new CounterInstrument( "lease-requests" );
226         m_stateSavesInstrument = new CounterInstrument( "state-saves" );
227         m_stateSaveTimeInstrument = new ValueInstrument( "state-save-time" );
228     }
229
230     /*---------------------------------------------------------------
231      * Configurable Methods
232      *-------------------------------------------------------------*/

233     /**
234      * Initializes the configured instrumentables.
235      *
236      * @param configuration InstrumentManager configuration.
237      *
238      * @throws ConfigurationException If there are any configuration problems.
239      */

240     public void configure( Configuration configuration )
241         throws ConfigurationException
242     {
243         m_translationLogger = getLogger().getChildLogger( "translation" );
244         
245         // Register the InstrumentManager as an Instrumentable. This must be done before
246
// the configuration and state file is loaded or our own instruments will not yet
247
// have proxies.
248
try
249         {
250             registerInstrumentable( this, getInstrumentableName() );
251         }
252         catch ( Exception JavaDoc e )
253         {
254             // Should never happen
255
throw new ConfigurationException(
256                 "Unable to register the InstrumentManager's own instruments.", e );
257         }
258
259         synchronized( m_semaphore )
260         {
261             // Look for a configured name and description
262
m_name = configuration.getChild( "name" ).getValue( "instrument-manager" );
263             m_description = configuration.getChild( "description" ).getValue( m_name );
264             
265             // Get configuration values which limit the leases that can be made.
266
m_maxLeasedSamples =
267                 configuration.getChild( "max-leased-samples" ).getValueAsInteger( 256 );
268             m_maxLeasedSampleSize =
269                 configuration.getChild( "max-leased-sample-size" ).getValueAsInteger( 2048 );
270             m_maxLeasedSampleLease = 1000L *
271                 configuration.getChild( "max-leased-sample-lease" ).getValueAsInteger( 86400 );
272             
273             // Configure any translations
274
Configuration translationsConf = configuration.getChild( "translations" );
275             Configuration[] translationConfs = translationsConf.getChildren( "translation" );
276             for( int i = 0; i < translationConfs.length; i++ )
277             {
278                 Configuration translationConf = translationConfs[i];
279                 String JavaDoc source = translationConf.getAttribute( "source" );
280                 String JavaDoc target = translationConf.getAttribute( "target" );
281                 try
282                 {
283                     registerNameTranslationInner( source, target );
284                 }
285                 catch ( IllegalArgumentException JavaDoc e )
286                 {
287                     throw new ConfigurationException( e.getMessage(), translationConf );
288                 }
289             }
290             
291             // Configure the instrumentables.
292
Configuration instrumentablesConf = configuration.getChild( "instrumentables" );
293             Configuration[] instrumentableConfs =
294                 instrumentablesConf.getChildren( "instrumentable" );
295             for( int i = 0; i < instrumentableConfs.length; i++ )
296             {
297                 Configuration instrumentableConf = instrumentableConfs[ i ];
298                 String JavaDoc instrumentableName = instrumentableConf.getAttribute( "name" );
299
300                 // See if the instrumentable already exists.
301
InstrumentableProxy instrumentableProxy =
302                     (InstrumentableProxy)m_instrumentableProxies.get( instrumentableName );
303                 if ( instrumentableProxy == null )
304                 {
305                     instrumentableProxy = new InstrumentableProxy(
306                         this, null, instrumentableName, instrumentableName );
307                     instrumentableProxy.enableLogging( getLogger() );
308                     incrementInstrumentableCount();
309                     m_instrumentableProxies.put( instrumentableName, instrumentableProxy );
310     
311                     // Clear the optimized arrays
312
m_instrumentableProxyArray = null;
313                     m_instrumentableDescriptorArray = null;
314                 }
315                 // Always configure
316
instrumentableProxy.configure( instrumentableConf );
317             }
318
319             // Configure the state file.
320
Configuration stateFileConf = configuration.getChild( "state-file" );
321             m_stateInterval = stateFileConf.getAttributeAsLong( "interval", 60000 );
322
323             String JavaDoc stateFile = stateFileConf.getValue( null );
324             if( stateFile != null )
325             {
326                 m_stateFile = new File JavaDoc( stateFile );
327                 if( m_stateFile.exists() )
328                 {
329                     try
330                     {
331                         loadStateFromFile( m_stateFile );
332                     }
333                     catch( Exception JavaDoc e )
334                     {
335                         String JavaDoc msg = "Unable to load the instrument manager state. The "
336                             + "configuration may have been corrupted. A backup may have been "
337                             + "made in the same directory when it was saved.";
338                         
339                         if ( getLogger().isDebugEnabled() )
340                         {
341                             getLogger().error( msg, e );
342                         }
343                         else
344                         {
345                             getLogger().error( msg + " : " + e.toString() );
346                         }
347                     }
348                 }
349             }
350             
351             // Create a logger to use with the connectors
352
Logger connLogger = getLogger().getChildLogger( "connector" );
353             
354             // Configure the connectors
355
Configuration connectorsConf = configuration.getChild( "connectors" );
356             Configuration[] connectorConfs =
357                 connectorsConf.getChildren( "connector" );
358             for( int i = 0; i < connectorConfs.length; i++ )
359             {
360                 Configuration connectorConf = connectorConfs[ i ];
361                 String JavaDoc className = connectorConf.getAttribute( "class" );
362                 // Handle aliases
363
if ( className.equals( "http" ) )
364                 {
365                     // Don't use InstrumentManagerAltrmiConnector.class.getName() because
366
// the class is optional for the build.
367
className = "org.apache.excalibur.instrument.manager.http."
368                         + "InstrumentManagerHTTPConnector";
369                 }
370                 
371                 // Look for the connector class and create an instance.
372
try
373                 {
374                     Class JavaDoc clazz = Class.forName( className );
375                     DefaultInstrumentManagerConnector connector =
376                         (DefaultInstrumentManagerConnector)clazz.newInstance();
377                     
378                     // Initialize the new connector
379
connector.setInstrumentManager( this );
380                     ContainerUtil.enableLogging( connector, connLogger );
381                     ContainerUtil.configure( connector, connectorConf );
382                     ContainerUtil.start( connector );
383                     if ( connector instanceof Instrumentable )
384                     {
385                         Instrumentable inst = (Instrumentable)connector;
386                         registerInstrumentable( inst,
387                             m_instrumentableName + ".connector." + inst.getInstrumentableName() );
388                     }
389                     
390                     m_connectors.add( connector );
391                 }
392                 catch ( Exception JavaDoc e )
393                 {
394                     String JavaDoc msg = "Unable to create connector because: " + e;
395                     
396                     // Was the optional flag set?
397
if ( connectorConf.getAttributeAsBoolean( "optional", true ) )
398                     {
399                         getLogger().warn( msg );
400                     }
401                     else
402                     {
403                         throw new ConfigurationException( msg );
404                     }
405                 }
406             }
407         }
408     }
409
410     /*---------------------------------------------------------------
411      * Initializable Methods
412      *-------------------------------------------------------------*/

413     /**
414      * Initializes the InstrumentManager.
415      *
416      * @throws Exception If there were any problems initializing the object.
417      */

418     public void initialize()
419         throws Exception JavaDoc
420     {
421         if( m_runner == null )
422         {
423             m_runner = new Thread JavaDoc( this, "InstrumentManagerRunner" );
424             m_runner.start();
425         }
426     }
427
428     /*---------------------------------------------------------------
429      * Disposable Methods
430      *-------------------------------------------------------------*/

431     /**
432      * Disposes the InstrumentManager.
433      */

434     public void dispose()
435     {
436         if( m_runner != null )
437         {
438             m_runner = null;
439         }
440         
441         // Shutdown the connectors
442
for ( Iterator JavaDoc iter = m_connectors.iterator(); iter.hasNext(); )
443         {
444             DefaultInstrumentManagerConnector connector =
445                 (DefaultInstrumentManagerConnector)iter.next();
446             try
447             {
448                 ContainerUtil.stop( connector );
449                 ContainerUtil.dispose( connector );
450             }
451             catch ( Exception JavaDoc e )
452             {
453                 getLogger().error( "Encountered an unexpected error shutting down a connector", e );
454             }
455         }
456
457         saveState();
458     }
459
460     /*---------------------------------------------------------------
461      * InstrumentManager Methods
462      *-------------------------------------------------------------*/

463     /**
464      * Instrumentable to be registered with the instrument manager. Should be
465      * called whenever an Instrumentable is created. The '.' character is
466      * used to denote a child Instrumentable and can be used to register the
467      * instrumentable at a specific point in an instrumentable hierarchy.
468      *
469      * @param instrumentable Instrumentable to register with the InstrumentManager.
470      * @param instrumentableName The name to use when registering the Instrumentable.
471      *
472      * @throws Exception If there were any problems registering the Instrumentable.
473      */

474     public void registerInstrumentable( Instrumentable instrumentable, String JavaDoc instrumentableName )
475         throws Exception JavaDoc
476     {
477         getLogger().debug( "Registering Instrumentable: " + instrumentableName );
478         
479         m_registrationsInstrument.increment();
480
481         synchronized( m_semaphore )
482         {
483             // If the specified instrumentable name contains '.' chars then we need to
484
// make sure we register the instrumentable at the correct location, creating
485
// any parent instrumentables as necessary.
486
int pos = instrumentableName.indexOf( '.' );
487             if ( pos >= 0 )
488             {
489                 String JavaDoc parentName = instrumentableName.substring( 0, pos );
490                 String JavaDoc childName =
491                     instrumentableName.substring( pos + 1 );
492                 InstrumentableProxy instrumentableProxy =
493                     (InstrumentableProxy)m_instrumentableProxies.get( parentName );
494                 if ( instrumentableProxy == null )
495                 {
496                     // This is a Instrumentable that has not been seen before.
497
instrumentableProxy = new InstrumentableProxy(
498                         this, null, parentName, parentName );
499                     instrumentableProxy.enableLogging( getLogger() );
500                     incrementInstrumentableCount();
501                     // Do not call configure here because there is no configuration
502
// for discovered instrumentables.
503
m_instrumentableProxies.put( parentName, instrumentableProxy );
504     
505                     // Clear the optimized arrays
506
m_instrumentableProxyArray = null;
507                     m_instrumentableDescriptorArray = null;
508     
509                     // Recursively register all the Instruments in this and any child Instrumentables.
510
registerDummyInstrumentableInner(
511                         instrumentable, instrumentableProxy, parentName, childName );
512                 }
513                 else
514                 {
515                     // Additional Instrumentable instance. Possible that new Instruments could be found.
516
registerDummyInstrumentableInner(
517                         instrumentable, instrumentableProxy, parentName, childName );
518                 }
519             } else {
520                 // If the instrumentable does not implement ThreadSafe, then it is possible that
521
// another one of its instance was already registered. If so, then the
522
// Instruments will all be the same. The new instances still need to be
523
// registered however.
524
InstrumentableProxy instrumentableProxy =
525                     (InstrumentableProxy)m_instrumentableProxies.get( instrumentableName );
526                 if( instrumentableProxy == null )
527                 {
528                     // This is a Instrumentable that has not been seen before.
529
instrumentableProxy = new InstrumentableProxy(
530                         this, null, instrumentableName, instrumentableName );
531                     instrumentableProxy.enableLogging( getLogger() );
532                     incrementInstrumentableCount();
533                     // Do not call configure here because there is no configuration
534
// for discovered instrumentables.
535
m_instrumentableProxies.put( instrumentableName, instrumentableProxy );
536     
537                     // Clear the optimized arrays
538
m_instrumentableProxyArray = null;
539                     m_instrumentableDescriptorArray = null;
540     
541                     // Recursively register all the Instruments in this and any child Instrumentables.
542
registerInstrumentableInner(
543                         instrumentable, instrumentableProxy, instrumentableName );
544                 }
545                 else
546                 {
547                     // Additional Instrumentable instance. Possible that new Instruments could be found.
548
registerInstrumentableInner(
549                         instrumentable, instrumentableProxy, instrumentableName );
550                 }
551             }
552         }
553         
554         stateChanged();
555     }
556
557     /*---------------------------------------------------------------
558      * DefaultInstrumentManager Methods
559      *-------------------------------------------------------------*/

560     /**
561      * Returns the name used to identify this DefaultInstrumentManager.
562      *
563      * @return The name used to identify this DefaultInstrumentManager.
564      */

565     public String JavaDoc getName()
566     {
567         return m_name;
568     }
569     
570     /**
571      * Returns the description of this DefaultInstrumentManager.
572      *
573      * @return The description of this DefaultInstrumentManager.
574      */

575     public String JavaDoc getDescription()
576     {
577         return m_description;
578     }
579     
580     /**
581      * Registers a name translation that will be applied to all named based
582      * lookups of instrumentables, instruments, and samples. The more
583      * translations that are registered, the greater the impact on name
584      * based lookups will be.
585      * <p>
586      * General operation of the instrument manager will not be affected as
587      * collection on sample data is always done using direct object
588      * references.
589      * <p>
590      * Translations can be registered for exact name matches, or for
591      * the bases of names. Any translation which ends in a '.' will
592      * imply a translation to any name beginning with that name base.
593      * If the source ends with a '.' then the target must as well.
594      *
595      * @param source The source name or name base of the translation.
596      * @param target The target name or name base of the translation.
597      *
598      * @throws IllegalArgumentException If the one but not both of the source
599      * and target parameters end in '.'.
600      */

601     public void registerNameTranslation( String JavaDoc source, String JavaDoc target )
602         throws IllegalArgumentException JavaDoc
603     {
604         synchronized( m_semaphore )
605         {
606             registerNameTranslationInner( source, target );
607         }
608     }
609     
610     /**
611      * Returns a InstrumentableDescriptor based on its name or the name of any
612      * of its children.
613      *
614      * @param instrumentableName Name of the Instrumentable being requested.
615      *
616      * @return A Descriptor of the requested Instrumentable.
617      *
618      * @throws NoSuchInstrumentableException If the specified Instrumentable
619      * does not exist.
620      */

621     public InstrumentableDescriptor getInstrumentableDescriptor( String JavaDoc instrumentableName )
622         throws NoSuchInstrumentableException
623     {
624         InstrumentableProxy proxy = getInstrumentableProxy( instrumentableName );
625         if( proxy == null )
626         {
627             throw new NoSuchInstrumentableException(
628                 "No instrumentable can be found using name: " + instrumentableName );
629         }
630
631         return proxy.getDescriptor();
632     }
633
634     /**
635      * Returns an array of Descriptors for the Instrumentables managed by this
636      * DefaultInstrumentManager.
637      *
638      * @return An array of InstrumentableDescriptors.
639      */

640     public InstrumentableDescriptor[] getInstrumentableDescriptors()
641     {
642         InstrumentableDescriptor[] descriptors = m_instrumentableDescriptorArray;
643         if( descriptors == null )
644         {
645             descriptors = updateInstrumentableDescriptorArray();
646         }
647         return descriptors;
648     }
649     
650     /**
651      * Searches the entire instrument tree for an instrumentable with the given
652      * name.
653      *
654      * @param instrumentableName Name of the Instrumentable being requested.
655      *
656      * @return A Descriptor of the requested Instrumentable.
657      *
658      * @throws NoSuchInstrumentableException If the specified Instrumentable
659      * does not exist.
660      */

661     public InstrumentableDescriptor locateInstrumentableDescriptor( String JavaDoc instrumentableName )
662         throws NoSuchInstrumentableException
663     {
664         InstrumentableProxy instrumentableProxy =
665             locateDeepestInstrumentableProxy( instrumentableName );
666         if ( instrumentableProxy != null )
667         {
668             if ( instrumentableProxy.getName().equals( instrumentableName ) )
669             {
670                 // Found what we were looking for
671
return instrumentableProxy.getDescriptor();
672             }
673         }
674         
675         // Unable to locate the requested Instrumentable
676
throw new NoSuchInstrumentableException(
677             "No instrumentable can be found with the name: " + instrumentableName );
678     }
679     
680     /**
681      * Searches the entire instrument tree for an instrument with the given
682      * name.
683      *
684      * @param instrumentName Name of the Instrument being requested.
685      *
686      * @return A Descriptor of the requested Instrument.
687      *
688      * @throws NoSuchInstrumentException If the specified Instrument does
689      * not exist.
690      */

691     public InstrumentDescriptor locateInstrumentDescriptor( String JavaDoc instrumentName )
692         throws NoSuchInstrumentException
693     {
694         InstrumentableProxy instrumentableProxy =
695             locateDeepestInstrumentableProxy( instrumentName );
696         if ( instrumentableProxy != null )
697         {
698             // Now look for the specified instrument
699
InstrumentProxy instrumentProxy =
700                 instrumentableProxy.getInstrumentProxy( instrumentName );
701             if ( instrumentProxy != null )
702             {
703                 if ( instrumentProxy.getName().equals( instrumentName ) )
704                 {
705                     // Found what we were looking for
706
return instrumentProxy.getDescriptor();
707                 }
708             }
709         }
710         
711         // Unable to locate the requested Instrument
712
throw new NoSuchInstrumentException(
713             "No instrument can be found with the name: " + instrumentName );
714     }
715
716     /**
717      * Searches the entire instrument tree for an instrument sample with the
718      * given name.
719      *
720      * @param sampleName Name of the Instrument Sample being requested.
721      *
722      * @return A Descriptor of the requested Instrument Sample.
723      *
724      * @throws NoSuchInstrumentSampleException If the specified Instrument
725      * Sample does not exist.
726      */

727     public InstrumentSampleDescriptor locateInstrumentSampleDescriptor( String JavaDoc sampleName )
728         throws NoSuchInstrumentSampleException
729     {
730         InstrumentableProxy instrumentableProxy =
731             locateDeepestInstrumentableProxy( sampleName );
732         if ( instrumentableProxy != null )
733         {
734             // Now look for the specified instrument
735
InstrumentProxy instrumentProxy =
736                 instrumentableProxy.getInstrumentProxy( sampleName );
737             if ( instrumentProxy != null )
738             {
739                 // Now look for the specified sample
740
InstrumentSample sample = instrumentProxy.getInstrumentSample( sampleName );
741                 if ( sample != null )
742                 {
743                     if ( sample.getName().equals( sampleName ) )
744                     {
745                         // Found what we were looking for
746
return sample.getDescriptor();
747                     }
748                 }
749             }
750         }
751         
752         // Unable to locate the requested Instrument Sample
753
throw new NoSuchInstrumentSampleException(
754             "No instrument sample can be found with the name: " + sampleName );
755     }
756
757     /**
758      * Returns the stateVersion of the DefaultInstrumeManager. The state
759      * version will be incremented each time any of the configuration of
760      * the instrument manager or any of its children is modified.
761      * <p>
762      * Clients can use this value to tell whether or not anything has
763      * changed without having to do an exhaustive comparison.
764      *
765      * @return The state version of the instrument manager.
766      */

767     public int getStateVersion()
768     {
769         return m_stateVersion;
770     }
771         
772     /**
773      * Invokes garbage collection.
774      */

775     public void invokeGarbageCollection()
776     {
777         System.gc();
778     }
779     
780     /**
781      * Returns the current number of leased samples.
782      *
783      * @return The current number of leased samples.
784      */

785     public int getLeaseSampleCount()
786     {
787         return m_leasedSampleCount;
788     }
789     
790     /**
791      * Returns the maximum number of leased samples that will be approved.
792      *
793      * @return The maximum number of leased samples.
794      */

795     public int getMaxLeasedSamples()
796     {
797         return m_maxLeasedSamples;
798     }
799     
800     /**
801      * Returns the maximum size of a leased sample.
802      *
803      * @return The maximum size of a leased sample.
804      */

805     public int getMaxLeasedSampleSize()
806     {
807         return m_maxLeasedSampleSize;
808     }
809     
810     /**
811      * Returns the maximum number of milliseconds that a lease will be granted
812      * for.
813      *
814      * @return The maximum lease length.
815      */

816     public long getMaxLeasedSampleLease()
817     {
818         return m_maxLeasedSampleLease;
819     }
820     
821     /*---------------------------------------------------------------
822      * Instrumentable Methods
823      *-------------------------------------------------------------*/

824     /**
825      * Sets the name for the Instrumentable. The Instrumentable Name is used
826      * to uniquely identify the Instrumentable during the configuration of
827      * the InstrumentManager and to gain access to an InstrumentableDescriptor
828      * through the InstrumentManager. The value should be a string which does
829      * not contain spaces or periods.
830      * <p>
831      * This value may be set by a parent Instrumentable, or by the
832      * InstrumentManager using the value of the 'instrumentable' attribute in
833      * the configuration of the component.
834      *
835      * @param name The name used to identify a Instrumentable.
836      */

837     public void setInstrumentableName( String JavaDoc name )
838     {
839         m_instrumentableName = name;
840     }
841
842     /**
843      * Gets the name of the Instrumentable.
844      *
845      * @return The name used to identify a Instrumentable.
846      */

847     public String JavaDoc getInstrumentableName()
848     {
849         return m_instrumentableName;
850     }
851
852     /**
853      * Obtain a reference to all the Instruments that the Instrumentable object
854      * wishes to expose. All sampling is done directly through the
855      * Instruments as opposed to the Instrumentable interface.
856      *
857      * @return An array of the Instruments available for profiling. Should
858      * never be null. If there are no Instruments, then
859      * EMPTY_INSTRUMENT_ARRAY can be returned. This should never be
860      * the case though unless there are child Instrumentables with
861      * Instruments.
862      */

863     public Instrument[] getInstruments()
864     {
865         return new Instrument[]
866         {
867             m_totalMemoryInstrument,
868             m_freeMemoryInstrument,
869             m_memoryInstrument,
870             m_activeThreadCountInstrument,
871             m_registrationsInstrument,
872             m_instrumentablesInstrument,
873             m_instrumentsInstrument,
874             m_samplesInstrument,
875             m_leasedSamplesInstrument,
876             m_leaseRequestsInstrument,
877             m_stateSavesInstrument,
878             m_stateSaveTimeInstrument
879         };
880     }
881
882     /**
883      * Any Object which implements Instrumentable can also make use of other
884      * Instrumentable child objects. This method is used to tell the
885      * InstrumentManager about them.
886      *
887      * @return An array of child Instrumentables. This method should never
888      * return null. If there are no child Instrumentables, then
889      * EMPTY_INSTRUMENTABLE_ARRAY can be returned.
890      */

891     public Instrumentable[] getChildInstrumentables()
892     {
893         return Instrumentable.EMPTY_INSTRUMENTABLE_ARRAY;
894     }
895
896     /*---------------------------------------------------------------
897      * Runnable Methods
898      *-------------------------------------------------------------*/

899     public void run()
900     {
901         while( m_runner != null )
902         {
903             try
904             {
905                 Thread.sleep( 1000 );
906
907                 memoryInstruments();
908                 threadInstruments();
909                 testInstrumentSampleLeases();
910
911                 // Handle the state file if it is set
912
long now = System.currentTimeMillis();
913                 if( now - m_lastStateSave >= m_stateInterval )
914                 {
915                     saveState();
916                 }
917             }
918             catch( Throwable JavaDoc t )
919             {
920                 getLogger().error( "Encountered an unexpected error.", t );
921             }
922         }
923     }
924     
925     /*---------------------------------------------------------------
926      * State File Methods
927      *-------------------------------------------------------------*/

928     /**
929      * Loads the Instrument Manager state from the specified file.
930      *
931      * @param stateFile File to read the instrument manager's state from.
932      *
933      * @throws Exception if there are any problems loading the state.
934      */

935     public void loadStateFromFile( File JavaDoc stateFile )
936         throws Exception JavaDoc
937     {
938         long now = System.currentTimeMillis();
939         getLogger().debug( "Loading Instrument Manager state from: " +
940             stateFile.getAbsolutePath() );
941
942         FileInputStream JavaDoc is = new FileInputStream JavaDoc( stateFile );
943         try
944         {
945             loadStateFromStream( is, stateFile.getCanonicalPath() );
946         }
947         finally
948         {
949             is.close();
950         }
951
952         getLogger().debug( "Loading Instrument Manager state took " +
953                            ( System.currentTimeMillis() - now ) + "ms." );
954     }
955
956     /**
957      * Loads the Instrument Manager state from the specified stream.
958      *
959      * @param is Stream to read the instrument manager's state from.
960      *
961      * @throws Exception if there are any problems loading the state.
962      */

963     public void loadStateFromStream( InputStream JavaDoc is )
964         throws Exception JavaDoc
965     {
966         loadStateFromStream( is, null );
967     }
968
969     /**
970      * Loads the Instrument Manager state from the specified stream.
971      *
972      * @param is Stream to read the instrument manager's state from.
973      * @param location The location of the stream. Used to improve the
974      * usefulness of any exceptions thrown.
975      *
976      * @throws Exception if there are any problems loading the state.
977      */

978     private void loadStateFromStream( InputStream JavaDoc is, String JavaDoc location )
979         throws Exception JavaDoc
980     {
981         // Ride on top of the Configuration classes to load the state.
982
DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
983         Configuration stateConfig;
984         if ( location == null )
985         {
986             stateConfig = builder.build( is );
987         }
988         else
989         {
990             stateConfig = builder.build( is, location );
991         }
992
993         loadStateFromConfiguration( stateConfig );
994     }
995
996     /**
997      * Loads the Instrument Manager state from the specified Configuration.
998      *
999      * @param state Configuration object to load the state from.
1000     *
1001     * @throws ConfigurationException If there were any problems loading the
1002     * state.
1003     */

1004    public void loadStateFromConfiguration( Configuration state )
1005        throws ConfigurationException
1006    {
1007        loadStateFromConfiguration( state, null );
1008    }
1009    
1010    private void loadStateFromConfiguration( Configuration state, String JavaDoc parentName )
1011        throws ConfigurationException
1012    {
1013        // When loading state, the only thing that we are really interrested in are the samples.
1014
// Don't bother looking anything up until one is found. Doing it this way is also
1015
// critical to make name translations work correctly.
1016

1017        // Drill down into Instrumentables and Instruments by recursing into this method.
1018
// This is not used by state files saved with version 2.2 or newer, but older
1019
// versions of the instrument manager saved their states in a tree structure.
1020
Configuration[] instrumentableConfs = state.getChildren( "instrumentable" );
1021        for( int i = 0; i < instrumentableConfs.length; i++ )
1022        {
1023            loadStateFromConfiguration(
1024                instrumentableConfs[i], instrumentableConfs[i].getAttribute( "name", null ) );
1025        }
1026        Configuration[] instrumentConfs = state.getChildren( "instrument" );
1027        for( int i = 0; i < instrumentConfs.length; i++ )
1028        {
1029            loadStateFromConfiguration(
1030                instrumentConfs[i], instrumentConfs[i].getAttribute( "name", null ) );
1031        }
1032        
1033        // Look for any samples.
1034
Configuration[] sampleConfs = state.getChildren( "sample" );
1035        for( int i = 0; i < sampleConfs.length; i++ )
1036        {
1037            Configuration sampleConf = sampleConfs[i];
1038            
1039            // Obtain and translate the sample name.
1040
String JavaDoc sampleName = sampleConf.getAttribute( "name", null );
1041            if ( sampleName == null )
1042            {
1043                // The sample name was missing. This can happen for very old state files.
1044
// Build the name.
1045
if ( parentName == null )
1046                {
1047                    throw new ConfigurationException(
1048                        "Unable to resolve sample name.", sampleConf );
1049                }
1050                
1051                int sampleType = InstrumentSampleUtils.resolveInstrumentSampleType(
1052                    sampleConf.getAttribute( "type" ) );
1053                long sampleInterval = sampleConf.getAttributeAsLong( "interval" );
1054                int sampleSize = sampleConf.getAttributeAsInteger( "size" );
1055                
1056                sampleName = InstrumentSampleUtils.generateFullInstrumentSampleName(
1057                    parentName, sampleType, sampleInterval, sampleSize );
1058            }
1059            // Translate the resulting name.
1060
sampleName = getTranslatedName( sampleName );
1061            
1062            // Before we do anything, decide how we want to handle the sample.
1063
long now = System.currentTimeMillis();
1064            long leaseExpirationTime = sampleConf.getAttributeAsLong( "lease-expiration", 0 );
1065            if ( leaseExpirationTime == 0 )
1066            {
1067                // This is the saved state of a permanent sample. We only want to load it
1068
// if the instrument and sample exists. If it does not exist then it means
1069
// that the user changed the configuration so the sample is no longer
1070
// permanent.
1071

1072                // Look for the existing instrument proxy.
1073
InstrumentProxy instrumentProxy = getInstrumentProxyForSample( sampleName, false );
1074                if ( instrumentProxy == null )
1075                {
1076                    // The instrument did not exist, so we want to skip this state.
1077
getLogger().info(
1078                        "Skipping old permantent sample from state due to missing instrument: "
1079                        + sampleName );
1080                }
1081                else
1082                {
1083                    // The instrument exists, but the sample may not. That is decided within
1084
// the instrument.
1085
InstrumentSample sample = instrumentProxy.loadSampleState( sampleConf );
1086                    if ( sample == null )
1087                    {
1088                        getLogger().info(
1089                            "Skipping old permantent sample from state: " + sampleName );
1090                    }
1091                    else
1092                    {
1093                        if ( getLogger().isDebugEnabled() )
1094                        {
1095                            getLogger().debug( "Load permanent sample state: " + sampleName );
1096                        }
1097                    }
1098                }
1099            }
1100            else if ( leaseExpirationTime > now )
1101            {
1102                // This is a leased sample that has not yet expired. Even if the sample
1103
// or even its instrument does not yet exist, we want to go ahead and
1104
// create it. It is possible for instruments and samples to be created
1105
// a while after the application has been started.
1106

1107                // Get the instrument. Will never return null.
1108
InstrumentProxy instrumentProxy = getInstrumentProxyForSample( sampleName, true );
1109                
1110                // Load the sample state.
1111
instrumentProxy.loadSampleState( sampleConf );
1112                
1113                if ( getLogger().isDebugEnabled() )
1114                {
1115                    getLogger().debug( "Load leased sample state : " + sampleName );
1116                }
1117            }
1118            else
1119            {
1120                // This sample has expired since the state was saved. Do nothing.
1121
if ( getLogger().isDebugEnabled() )
1122                {
1123                    getLogger().debug( "Skip expired sample state: " + sampleName );
1124                }
1125            }
1126        }
1127        
1128        // If anything was actually loaded then stateChanged() will be called from the samples.
1129
}
1130
1131    /**
1132     * Saves the Instrument Manager's state to the specified file. Any
1133     * existing file is backed up before the save takes place and replaced
1134     * in the event of an error.
1135     *
1136     * @param stateFile File to write the Instrument Manager's state to.
1137     *
1138     * @throws Exception if there are any problems saving the state.
1139     */

1140    public void saveStateToFile( File JavaDoc stateFile )
1141        throws Exception JavaDoc
1142    {
1143        long now = System.currentTimeMillis();
1144        getLogger().debug( "Saving Instrument Manager state to: " + stateFile.getAbsolutePath() );
1145        
1146        // To make corruption as unlikely as possible, write the state file to a
1147
// temporary file. Only overwrite the previous state file when complete.
1148
File JavaDoc tempFile = new File JavaDoc( stateFile.getAbsolutePath() + "." + now + ".temp" );
1149        boolean success = false;
1150        FileOutputStream JavaDoc fos = new FileOutputStream JavaDoc( tempFile );
1151        try
1152        {
1153            saveStateToStream( fos );
1154            success = true;
1155        }
1156        finally
1157        {
1158            fos.close();
1159            
1160            File JavaDoc renameFile = null;
1161            try
1162            {
1163                if ( success )
1164                {
1165                    // Rename the old state file first of all.
1166
if ( stateFile.exists() )
1167                    {
1168                        renameFile =
1169                            new File JavaDoc( stateFile.getAbsolutePath() + "." + now + ".backup" );
1170                        if ( !stateFile.renameTo( renameFile ) )
1171                        {
1172                            throw new IOException JavaDoc(
1173                                "Unable to rename the old instrument state file from '"
1174                                + stateFile.getAbsolutePath() + "' to '"
1175                                + renameFile.getAbsolutePath() + "'" );
1176                        }
1177                    }
1178                    
1179                    // Now rename the new temp state file to the final name.
1180
if ( !tempFile.renameTo( stateFile ) )
1181                    {
1182                        if ( renameFile != null )
1183                        {
1184                            // Attempt to restore the old state file.
1185
if ( !renameFile.renameTo( stateFile ) )
1186                            {
1187                                // Failed for some reason.
1188
getLogger().error(
1189                                    "Unable to save the instrument state. The last known state "
1190                                    + "file is backed up as: " + renameFile.getAbsolutePath() );
1191                                
1192                                // Clear the rename file so it does not get deleted.
1193
renameFile = null;
1194                            }
1195                        }
1196                        
1197                        throw new IOException JavaDoc(
1198                            "Unable to rename the new instrument state file from '"
1199                            + tempFile.getAbsolutePath() + "' to '"
1200                            + stateFile.getAbsolutePath() + "'" );
1201                    }
1202                    else
1203                    {
1204                        // Temp fle renamed, so clear its name.
1205
tempFile = null;
1206                    }
1207                }
1208            }
1209            finally
1210            {
1211                // Delete the temp file if it still exists.
1212
if ( ( tempFile != null ) && tempFile.exists() )
1213                {
1214                    if ( !tempFile.delete() )
1215                    {
1216                        getLogger().warn( "Unable to delete temporary state file: "
1217                            + tempFile.getAbsolutePath() );
1218                    }
1219                }
1220                
1221                // Delete the rename file if it still exists.
1222
if ( ( renameFile != null ) && renameFile.exists() )
1223                {
1224                    if ( !renameFile.delete() )
1225                    {
1226                        getLogger().warn( "Unable to delete temporary state file: "
1227                            + renameFile.getAbsolutePath() );
1228                    }
1229                }
1230            }
1231        }
1232        
1233        getLogger().debug( "Saving Instrument Manager state took " +
1234                           ( System.currentTimeMillis() - now ) + "ms." );
1235    }
1236
1237    /**
1238     * Saves the Instrument Manager's state to the specified output stream.
1239     *
1240     * @param os Stream to write the Instrument Manager's state to.
1241     *
1242     * @throws Exception if there are any problems saving the state.
1243     */

1244    public void saveStateToStream( OutputStream JavaDoc os )
1245        throws Exception JavaDoc
1246    {
1247        // We used to create a big Configuration object and then write it to an output
1248
// stream. While that worked, on applications with lots of samples, it
1249
// could result in very large Configuration objects that would cause a large
1250
// spike in memory usage when the state was saved.
1251
// The new method writes directly to the file thus avoiding the need for any
1252
// significant amount of memory.
1253
PrintWriter JavaDoc out = new PrintWriter JavaDoc( new OutputStreamWriter JavaDoc( os, "UTF-8" ) );
1254        
1255        // Output the XML headers and main node.
1256
out.println( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" );
1257        out.println( "<instrument-manager-state>" );
1258
1259        InstrumentableProxy[] instrumentableProxies = m_instrumentableProxyArray;
1260        if( instrumentableProxies == null )
1261        {
1262            instrumentableProxies = updateInstrumentableProxyArray();
1263        }
1264        
1265        for( int i = 0; i < instrumentableProxies.length; i++ )
1266        {
1267            instrumentableProxies[i].writeState( out );
1268        }
1269    
1270        // Close off the main node.
1271
out.println( "</instrument-manager-state>" );
1272        
1273        // We don't want to close the writer here or it will close the underlying stream
1274
// Do the next best thing by flushing to make sure that nothing is left unflushed
1275
// in writer buffers.
1276
out.flush();
1277    }
1278
1279    /*---------------------------------------------------------------
1280     * Package Methods
1281     *-------------------------------------------------------------*/

1282    /**
1283     * Registers an InstrumentSample which has been leased so that the
1284     * Instrument Manager can efficiently purge it when it has expired.
1285     *
1286     * @param instrumentSample Leased InstrumentSample to register.
1287     */

1288    void registerLeasedInstrumentSample( InstrumentSample instrumentSample )
1289    {
1290        synchronized( m_leasedInstrumentSamples )
1291        {
1292            // Make sure that the sample is really leased.
1293
if ( instrumentSample.getLeaseExpirationTime() <= 0 )
1294            {
1295                throw new IllegalStateException JavaDoc( "Got an InstrumentSample that was not leased." );
1296            }
1297            
1298            // Make sure that it is not already in the list.
1299
if ( m_leasedInstrumentSamples.indexOf( instrumentSample ) < 0 )
1300            {
1301                m_leasedInstrumentSamples.add( instrumentSample );
1302                m_leasedInstrumentSampleArray = null;
1303            }
1304        }
1305    }
1306    
1307    /**
1308     * Called whenever the state of the instrument manager is changed.
1309     */

1310    void stateChanged()
1311    {
1312        m_stateVersion++;
1313    }
1314    
1315    /**
1316     * Called to increment the number of Instrumentables registered.
1317     */

1318    void incrementInstrumentableCount()
1319    {
1320        int count;
1321        synchronized( m_semaphore )
1322        {
1323            count = ++m_instrumentableCount;
1324        }
1325        m_instrumentablesInstrument.setValue( count );
1326    }
1327    
1328    /**
1329     * Called to increment the number of Instruments registered.
1330     */

1331    void incrementInstrumentCount()
1332    {
1333        int count;
1334        synchronized( m_semaphore )
1335        {
1336            count = ++m_instrumentCount;
1337        }
1338        m_instrumentsInstrument.setValue( count );
1339    }
1340    
1341    /**
1342     * Called to increment the number of Permanent Instrument Samples registered.
1343     */

1344    void incrementPermanentSampleCount()
1345    {
1346        int count;
1347        synchronized( m_semaphore )
1348        {
1349            count = ++m_permanentSampleCount + m_leasedSampleCount;
1350        }
1351        m_samplesInstrument.setValue( count );
1352    }
1353    
1354    /**
1355     * Called to increment the number of Leased Instrument Samples registered.
1356     */

1357    void incrementLeasedSampleCount()
1358    {
1359        int count;
1360        int leasedCount;
1361        synchronized( m_semaphore )
1362        {
1363            leasedCount = ++m_leasedSampleCount;
1364            count = m_permanentSampleCount + m_leasedSampleCount;
1365        }
1366        m_samplesInstrument.setValue( count );
1367        m_leasedSamplesInstrument.setValue( leasedCount );
1368    }
1369    
1370    /**
1371     * Called to decrement the number of Leased Instrument Samples registered.
1372     */

1373    void decrementLeasedSampleCount()
1374    {
1375        int count;
1376        int leasedCount;
1377        synchronized( m_semaphore )
1378        {
1379            leasedCount = --m_leasedSampleCount;
1380            count = m_permanentSampleCount + m_leasedSampleCount;
1381        }
1382        m_samplesInstrument.setValue( count );
1383        m_leasedSamplesInstrument.setValue( leasedCount );
1384    }
1385    
1386    /**
1387     * Increment the lease requests.
1388     */

1389    void incrementLeaseRequests()
1390    {
1391        m_leaseRequestsInstrument.increment();
1392    }
1393    
1394    /*---------------------------------------------------------------
1395     * Private Methods
1396     *-------------------------------------------------------------*/

1397    /**
1398     * Saves the state to the current state file if configured.
1399     */

1400    private void saveState()
1401    {
1402        long now = System.currentTimeMillis();
1403
1404        // Always set the time even if the save fails so that we don't thrash
1405
m_lastStateSave = now;
1406
1407        if( m_stateFile == null )
1408        {
1409            return;
1410        }
1411        
1412        try
1413        {
1414            saveStateToFile( m_stateFile );
1415        }
1416        catch ( Exception JavaDoc e )
1417        {
1418            String JavaDoc msg = "Unable to save the Instrument Manager state";
1419            if ( getLogger().isDebugEnabled() )
1420            {
1421                getLogger().warn( msg, e );
1422            }
1423            else
1424            {
1425                getLogger().warn( msg + " : " + e.toString() );
1426            }
1427        }
1428        
1429        m_stateSavesInstrument.increment();
1430        m_stateSaveTimeInstrument.setValue( (int)( System.currentTimeMillis() - now ) );
1431    }
1432    
1433    /**
1434     * Updates the cached array of registered name translations taking
1435     * synchronization into account.
1436     *
1437     * @return An array of the String[2]s representing the registered name
1438     * translations.
1439     */

1440    private String JavaDoc[][] updateNameTranslationArray()
1441    {
1442        synchronized( m_semaphore )
1443        {
1444            String JavaDoc[][] nameTranslations = new String JavaDoc[m_nameTranslations.size()][2];
1445            int i = 0;
1446            for ( Iterator JavaDoc iter = m_nameTranslations.entrySet().iterator(); iter.hasNext(); i++ )
1447            {
1448                Map.Entry JavaDoc entry = (Map.Entry JavaDoc)iter.next();
1449                nameTranslations[i][0] = (String JavaDoc)entry.getKey();
1450                nameTranslations[i][1] = (String JavaDoc)entry.getValue();
1451            }
1452            
1453            // Once we are done modifying this array, set it to the variable accessable outside
1454
// of synchronization.
1455
m_nameTranslationArray = nameTranslations;
1456            
1457            return nameTranslations;
1458        }
1459    }
1460    
1461    /**
1462     * Translates a item name depending on a set of configured translations.
1463     * If the name does not exist as a translation then the requested name will
1464     * be returned unmodified.
1465     *
1466     * @param name Requested name.
1467     *
1468     * @return target name.
1469     */

1470    String JavaDoc getTranslatedName( String JavaDoc name )
1471    {
1472        String JavaDoc[][] nameTranslations = m_nameTranslationArray;
1473        if( nameTranslations == null )
1474        {
1475            nameTranslations = updateNameTranslationArray();
1476        }
1477        
1478        for ( int i = 0; i < nameTranslations.length; i++ )
1479        {
1480            String JavaDoc[] nameTranslation = nameTranslations[i];
1481            
1482            if ( name.startsWith( nameTranslation[0] ) )
1483            {
1484                // Match
1485
if ( name.equals( nameTranslation[0] ) )
1486                {
1487                    // Exact match
1488
String JavaDoc newName = nameTranslation[1];
1489                    
1490                    if ( m_translationLogger.isDebugEnabled() )
1491                    {
1492                        m_translationLogger.debug(
1493                            "Translate \"" + name + "\" to \"" + newName + "\"" );
1494                    }
1495                    
1496                    return newName;
1497                }
1498                else if ( nameTranslation[0].endsWith( "." ) )
1499                {
1500                    // Beginning match
1501
String JavaDoc newName =
1502                        nameTranslation[1] + name.substring( nameTranslation[0].length() );
1503                    
1504                    if ( m_translationLogger.isDebugEnabled() )
1505                    {
1506                        m_translationLogger.debug(
1507                            "Translate \"" + name + "\" to \"" + newName + "\"" );
1508                    }
1509                    
1510                    return newName;
1511                }
1512                else
1513                {
1514                    // The name happened to match the beginning of this name, but it was not meant
1515
// as a base translation.
1516
}
1517            }
1518        }
1519        
1520        // No match.
1521
return name;
1522    }
1523    
1524    /**
1525     */

1526    private InstrumentableProxy getInstrumentableProxy( String JavaDoc instrumentableName, boolean create )
1527    {
1528        //getLogger().debug( "getInstrumentableProxy( " + instrumentableName + ", " + create + " )" );
1529
// The instrumable name may begin with the name of a parent Instrumentable
1530
int pos = instrumentableName.lastIndexOf( '.' );
1531        if ( pos <= 0 )
1532        {
1533            // This is a root level instrumentable. Look for it within the Instrument Manager.
1534
InstrumentableProxy instrumentableProxy;
1535            synchronized( m_semaphore )
1536            {
1537                instrumentableProxy =
1538                    (InstrumentableProxy)m_instrumentableProxies.get( instrumentableName );
1539                
1540                if ( ( instrumentableProxy == null ) && create )
1541                {
1542                    //getLogger().debug( " New Instrumentable" );
1543
// Not found, create it.
1544
instrumentableProxy = new InstrumentableProxy(
1545                        this, null, instrumentableName, instrumentableName );
1546                    instrumentableProxy.enableLogging( getLogger() );
1547                    incrementInstrumentableCount();
1548                    m_instrumentableProxies.put( instrumentableName, instrumentableProxy );
1549    
1550                    // Clear the optimized arrays
1551
m_instrumentableProxyArray = null;
1552                    m_instrumentableDescriptorArray = null;
1553                }
1554            }
1555            
1556            //getLogger().debug( " -> " + instrumentableProxy );
1557
return instrumentableProxy;
1558        }
1559        else
1560        {
1561            String JavaDoc parentInstrumentableName = instrumentableName.substring( 0, pos );
1562            
1563            // See if the parent Instrumentable exists.
1564
InstrumentableProxy parentInstrumentableProxy =
1565                getInstrumentableProxy( parentInstrumentableName, create );
1566            if ( parentInstrumentableProxy == null )
1567            {
1568                // Parent Instrumentable did not exist, so the Instrumentable did not exist.
1569
// Will not get here if create is true.
1570
return null;
1571            }
1572            
1573            // Locate the Instrumentable within the parent Instrumentable.
1574
return parentInstrumentableProxy.getChildInstrumentableProxy(
1575                instrumentableName, create );
1576        }
1577    }
1578    
1579    /**
1580     * @throws IllegalArgumentException If the specified instrumentName is invalid.
1581     */

1582    private InstrumentProxy getInstrumentProxy( String JavaDoc instrumentName, boolean create )
1583        throws IllegalArgumentException JavaDoc
1584    {
1585        //getLogger().debug( "getInstrumentProxy( " + instrumentName + ", " + create + " )" );
1586
// The instrument name must always begin with the name of an Instrumentable
1587
int pos = instrumentName.lastIndexOf( '.' );
1588        if ( pos <= 0 )
1589        {
1590            throw new IllegalArgumentException JavaDoc(
1591                "\"" + instrumentName + "\" is not a valid instrument name." );
1592        }
1593        String JavaDoc instrumentableName = instrumentName.substring( 0, pos );
1594        
1595        // See if the Instrumentable exists.
1596
InstrumentableProxy instrumentableProxy =
1597            getInstrumentableProxy( instrumentableName, create );
1598        if ( instrumentableProxy == null )
1599        {
1600            // Instrumentable did not exist, so the instrument did not exist. Will not get here
1601
// if create is true.
1602
return null;
1603        }
1604        
1605        // Locate the instrument within the Instrumentable.
1606
return instrumentableProxy.getInstrumentProxy( instrumentName, create );
1607    }
1608    
1609    /**
1610     * @throws IllegalArgumentException If the specified sampleName is invalid.
1611     */

1612    private InstrumentProxy getInstrumentProxyForSample( String JavaDoc sampleName, boolean create )
1613        throws IllegalArgumentException JavaDoc
1614    {
1615        //getLogger().debug( "getInstrumentProxyForSample( " + sampleName + ", " + create + " )" );
1616
// The sample name must always begin with the name of an Instrument
1617
int pos = sampleName.lastIndexOf( '.' );
1618        if ( pos <= 0 )
1619        {
1620            throw new IllegalArgumentException JavaDoc(
1621                "\"" + sampleName + "\" is not a valid instrument sample name." );
1622        }
1623        String JavaDoc instrumentName = sampleName.substring( 0, pos );
1624        
1625        // Lookup the Instrument.
1626
return getInstrumentProxy( instrumentName, create );
1627    }
1628    
1629    /**
1630     * Returns a InstrumentableDescriptor based on its name or the name of any
1631     * of its children.
1632     *
1633     * @param instrumentableName Name of the Instrumentable being requested.
1634     *
1635     * @return A Proxy of the requested Instrumentable or null if not found.
1636     */

1637    private InstrumentableProxy getInstrumentableProxy( String JavaDoc instrumentableName )
1638    {
1639        String JavaDoc name = instrumentableName;
1640        while( true )
1641        {
1642            InstrumentableProxy proxy = (InstrumentableProxy)m_instrumentableProxies.get( name );
1643            if( proxy != null )
1644            {
1645                return proxy;
1646            }
1647
1648            // Assume this is a child name and try looking with the parent name.
1649
int pos = name.lastIndexOf( '.' );
1650            if( pos > 0 )
1651            {
1652                name = name.substring( 0, pos );
1653            }
1654            else
1655            {
1656                return null;
1657            }
1658        }
1659    }
1660    
1661    /**
1662     * Given the name of an instrumentable proxy, locate the deepest child
1663     * instrumentable given the name. The name can be the name of an
1664     * instrumentable or of any of its children.
1665     *
1666     * @param instrumentableName Fully qualified name of the instrumentable
1667     * being requested, or of any of its children.
1668     *
1669     * @return The requested instrumentable, or null if not found.
1670     */

1671    private InstrumentableProxy locateDeepestInstrumentableProxy( String JavaDoc instrumentableName )
1672    {
1673        InstrumentableProxy deepestProxy = null;
1674        // Start by obtaining a top level instrumentable
1675
InstrumentableProxy proxy = getInstrumentableProxy( instrumentableName );
1676        
1677        // Now attempt to locate a child instrumentable
1678
while ( proxy != null )
1679        {
1680            deepestProxy = proxy;
1681            
1682            proxy = deepestProxy.getChildInstrumentableProxy( instrumentableName );
1683        }
1684        
1685        return deepestProxy;
1686    }
1687
1688    /**
1689     * Updates the Memory based Profile Points published by the InstrumentManager.
1690     */

1691    private void memoryInstruments()
1692    {
1693        // Avoid doing unneeded work if profile points are not being used.
1694
Runtime JavaDoc runtime = null;
1695        long totalMemory = -1;
1696        long freeMemory = -1;
1697
1698        // Total Memory
1699
if( m_totalMemoryInstrument.isActive() )
1700        {
1701            runtime = Runtime.getRuntime();
1702            totalMemory = runtime.totalMemory();
1703            m_totalMemoryInstrument.setValue( (int)totalMemory );
1704        }
1705
1706        // Free Memory
1707
if( m_freeMemoryInstrument.isActive() )
1708        {
1709            if( runtime == null )
1710            {
1711                runtime = Runtime.getRuntime();
1712            }
1713            freeMemory = runtime.freeMemory();
1714            m_freeMemoryInstrument.setValue( (int)freeMemory );
1715        }
1716
1717        // In use Memory
1718
if( m_memoryInstrument.isActive() )
1719        {
1720            if( runtime == null )
1721            {
1722                runtime = Runtime.getRuntime();
1723            }
1724            if( totalMemory < 0 )
1725            {
1726                totalMemory = runtime.totalMemory();
1727            }
1728            if( freeMemory < 0 )
1729            {
1730                freeMemory = runtime.freeMemory();
1731            }
1732            m_memoryInstrument.setValue( (int)( totalMemory - freeMemory ) );
1733        }
1734    }
1735
1736    /**
1737     * Updates the Thread based Profile Points published by the InstrumentManager.
1738     */

1739    private void threadInstruments()
1740    {
1741        if( m_activeThreadCountInstrument.isActive() )
1742        {
1743            // Get the top level thread group.
1744
ThreadGroup JavaDoc threadGroup = Thread.currentThread().getThreadGroup();
1745            ThreadGroup JavaDoc parent;
1746            while( ( parent = threadGroup.getParent() ) != null )
1747            {
1748                threadGroup = parent;
1749            }
1750
1751            m_activeThreadCountInstrument.setValue( threadGroup.activeCount() );
1752        }
1753    }
1754    
1755    /**
1756     * Handles the maintenance of all Instrument Samples which have been leased
1757     * by a client. Any Samples whose leases which have expired are cleaned
1758     * up.
1759     */

1760    private void testInstrumentSampleLeases()
1761    {
1762        long now = System.currentTimeMillis();
1763        
1764        InstrumentSample[] samples;
1765        synchronized( m_leasedInstrumentSamples )
1766        {
1767            samples = m_leasedInstrumentSampleArray;
1768            if ( samples == null )
1769            {
1770                m_leasedInstrumentSampleArray =
1771                    new InstrumentSample[ m_leasedInstrumentSamples.size() ];
1772                m_leasedInstrumentSamples.toArray( m_leasedInstrumentSampleArray );
1773                samples = m_leasedInstrumentSampleArray;
1774            }
1775        }
1776        
1777        for ( int i = 0; i < samples.length; i++ )
1778        {
1779            InstrumentSample sample = samples[i];
1780            long expire = sample.getLeaseExpirationTime();
1781            if ( now >= expire )
1782            {
1783                // The sample lease has expired.
1784
InstrumentProxy instrument = sample.getInstrumentProxy();
1785                instrument.removeInstrumentSample( sample );
1786                sample.expire();
1787                
1788                m_leasedInstrumentSamples.remove( sample );
1789                m_leasedInstrumentSampleArray = null;
1790            }
1791        }
1792    }
1793    
1794    /**
1795     * Updates the cached array of InstrumentableProxies taking
1796     * synchronization into account.
1797     *
1798     * @return An array of the InstrumentableProxies.
1799     */

1800    private InstrumentableProxy[] updateInstrumentableProxyArray()
1801    {
1802        synchronized( m_semaphore )
1803        {
1804            InstrumentableProxy[] instrumentableProxyArray =
1805                new InstrumentableProxy[ m_instrumentableProxies.size() ];
1806            m_instrumentableProxies.values().toArray( instrumentableProxyArray );
1807
1808            // Sort the array. This is not a performance problem because this
1809
// method is rarely called and doing it here saves cycles in the
1810
// client.
1811
Arrays.sort( instrumentableProxyArray, new Comparator JavaDoc()
1812                {
1813                    public int compare( Object JavaDoc o1, Object JavaDoc o2 )
1814                    {
1815                        return ((InstrumentableProxy)o1).getDescription().
1816                            compareTo( ((InstrumentableProxy)o2).getDescription() );
1817                    }
1818                    
1819                    public boolean equals( Object JavaDoc obj )
1820                    {
1821                        return false;
1822                    }
1823                } );
1824            
1825            // Once we are done modifying this array, set it to the variable accessable outside
1826
// of synchronization.
1827
m_instrumentableProxyArray = instrumentableProxyArray;
1828            
1829            return instrumentableProxyArray;
1830        }
1831    }
1832
1833    /**
1834     * Updates the cached array of InstrumentableDescriptors taking
1835     * synchronization into account.
1836     *
1837     * @return An array of the InstrumentableDescriptors.
1838     */

1839    private InstrumentableDescriptor[] updateInstrumentableDescriptorArray()
1840    {
1841        synchronized( m_semaphore )
1842        {
1843            // Get the proxy array. This is done in synchronization so it is not possible that it
1844
// will be reset before we obtain the descriptor array. They are both set to null
1845
// at the same time when there is a change.
1846
InstrumentableProxy[] instrumentableProxyArray = m_instrumentableProxyArray;
1847            if ( instrumentableProxyArray == null )
1848            {
1849                instrumentableProxyArray = updateInstrumentableProxyArray();
1850            }
1851            
1852            InstrumentableDescriptor[] instrumentableDescriptorArray =
1853                new InstrumentableDescriptor[ instrumentableProxyArray.length ];
1854            for( int i = 0; i < instrumentableProxyArray.length; i++ )
1855            {
1856                instrumentableDescriptorArray[ i ] = instrumentableProxyArray[ i ].getDescriptor();
1857            }
1858            
1859            // Once we are done modifying this array, set it to the variable accessable outside
1860
// of synchronization.
1861
m_instrumentableDescriptorArray = instrumentableDescriptorArray;
1862            
1863            return instrumentableDescriptorArray;
1864        }
1865    }
1866    
1867    /**
1868     * Registers a name translation that will be applied to all named based
1869     * lookups of instrumentables, instruments, and samples. The more
1870     * translations that are registered, the greater the impact on name
1871     * based lookups will be.
1872     * <p>
1873     * General operation of the instrument manager will not be affected as
1874     * collection on sample data is always done using direct object
1875     * references.
1876     * <p>
1877     * Translations can be registered for translations of sample names up to
1878     * and including the name of the instrument. This means that all source
1879     * and target names must end in a '.'.
1880     * <p>
1881     * This method should only be called when m_semaphore is synchronized.
1882     *
1883     * @param source The source name or name base of the translation.
1884     * @param target The target name or name base of the translation.
1885     *
1886     * @throws IllegalArgumentException If either the source or target does
1887     * not end in a '.' or is invalid.
1888     */

1889    private void registerNameTranslationInner( String JavaDoc source, String JavaDoc target )
1890        throws IllegalArgumentException JavaDoc
1891    {
1892        if ( !source.endsWith( "." ) )
1893        {
1894            throw new IllegalArgumentException JavaDoc( "The translation source must end with a '.'." );
1895        }
1896        if ( !target.endsWith( "." ) )
1897        {
1898            throw new IllegalArgumentException JavaDoc( "The translation target must end with a '.'." );
1899        }
1900        
1901        // No component of the source or target name may be 0 length.
1902
if ( source.startsWith( "." ) || ( source.indexOf( ".." ) >= 0 ) )
1903        {
1904            throw new IllegalArgumentException JavaDoc(
1905                "The translation source is invalid: \"" + source + "\"." );
1906        }
1907        if ( target.startsWith( "." ) || ( target.indexOf( ".." ) >= 0 ) )
1908        {
1909            throw new IllegalArgumentException JavaDoc(
1910                "The translation target is invalid: \"" + target + "\"." );
1911        }
1912        
1913        m_nameTranslations.put( source, target );
1914        m_nameTranslationArray = null;
1915    }
1916
1917    /**
1918     * Called as a place holder to handle the registration of instrumentables
1919     * that do not really exist. This makes it possible to register
1920     * instrumentables at arbitrary locations in the instrumentable hierarchy.
1921     *
1922     * @param instrumentable The instrumentable that was registered below a dummy
1923     * parent.
1924     * @param instrumentableProxy The proxy assigned to the current placeholder
1925     * instrumentable.
1926     * @param instrumentableName The name of the current placeholder
1927     * instrumentable.
1928     * @param childName The name of the child instrumentable to register. May
1929     * contain further '.' characters.
1930     */

1931    private void registerDummyInstrumentableInner( Instrumentable instrumentable,
1932                                                   InstrumentableProxy instrumentableProxy,
1933                                                   String JavaDoc instrumentableName,
1934                                                   String JavaDoc childName )
1935        throws Exception JavaDoc
1936    {
1937        // If the specified instrumentable name contains '.' chars then we need to
1938
// make sure we register the instrumentable at the correct location, creating
1939
// any parent instrumentables as necessary.
1940
int pos = childName.indexOf( '.' );
1941        if ( pos >= 0 )
1942        {
1943            String JavaDoc newParentName = childName.substring( 0, pos );
1944            String JavaDoc newChildName =
1945                childName.substring( pos + 1 );
1946            
1947            String JavaDoc fullChildName = instrumentableName + "." + newParentName;
1948            
1949            getLogger().debug( "Registering Child Instrumentable: " + fullChildName );
1950            
1951            // See if a proxy exists for the child Instrumentable yet.
1952
InstrumentableProxy proxy =
1953                instrumentableProxy.getChildInstrumentableProxy( fullChildName );
1954            if( proxy == null )
1955            {
1956                proxy = new InstrumentableProxy(
1957                    this, instrumentableProxy, fullChildName, newParentName );
1958                proxy.enableLogging( getLogger() );
1959                incrementInstrumentableCount();
1960                
1961                instrumentableProxy.addChildInstrumentableProxy( proxy );
1962            }
1963            
1964            // Recurse to the child
1965
registerDummyInstrumentableInner( instrumentable, proxy, fullChildName, newChildName );
1966        }
1967        else
1968        {
1969            // The child does not contain and '.' characters, so we are at the correct location.
1970
String JavaDoc fullChildName = instrumentableName + "." + childName;
1971            
1972            getLogger().debug( "Registering Child Instrumentable: " + fullChildName );
1973            
1974            // See if a proxy exists for the child Instrumentable yet.
1975
InstrumentableProxy proxy =
1976                instrumentableProxy.getChildInstrumentableProxy( fullChildName );
1977            if( proxy == null )
1978            {
1979                proxy = new InstrumentableProxy(
1980                    this, instrumentableProxy, fullChildName, childName );
1981                proxy.enableLogging( getLogger() );
1982                incrementInstrumentableCount();
1983                
1984                instrumentableProxy.addChildInstrumentableProxy( proxy );
1985            }
1986            
1987            // Recurse to the child
1988
registerInstrumentableInner( instrumentable, proxy, fullChildName );
1989        }
1990    }
1991
1992    /**
1993     * Examines a instrumentable and Registers all of its child Instrumentables
1994     * and Instruments.
1995     * <p>
1996     * Only called when m_semaphore is locked.
1997     */

1998    private void registerInstrumentableInner( Instrumentable instrumentable,
1999                                              InstrumentableProxy instrumentableProxy,
2000                                              String JavaDoc instrumentableName )
2001        throws Exception JavaDoc
2002    {
2003        // Mark the instrumentable proxy as registered.
2004
instrumentableProxy.setRegistered();
2005
2006        // Loop over the Instruments published by this Instrumentable
2007
Instrument[] instruments = instrumentable.getInstruments();
2008        for( int i = 0; i < instruments.length; i++ )
2009        {
2010            Instrument instrument = instruments[ i ];
2011            String JavaDoc instrumentName = instrument.getInstrumentName();
2012            String JavaDoc fullInstrumentName = instrumentableName + "." + instrumentName;
2013
2014            getLogger().debug( "Registering Instrument: " + fullInstrumentName );
2015
2016            // See if a proxy exists for the Instrument yet.
2017
InstrumentProxy proxy = instrumentableProxy.getInstrumentProxy( fullInstrumentName );
2018            if( proxy == null )
2019            {
2020                proxy = new InstrumentProxy(
2021                    instrumentableProxy, fullInstrumentName, instrumentName );
2022                proxy.enableLogging( getLogger() );
2023                incrementInstrumentCount();
2024
2025                // Set the type of the new InstrumentProxy depending on the
2026
// class of the actual Instrument.
2027
if( instrument instanceof CounterInstrument )
2028                {
2029                    proxy.setType( DefaultInstrumentManager.INSTRUMENT_TYPE_COUNTER );
2030                }
2031                else if( instrument instanceof ValueInstrument )
2032                {
2033                    proxy.setType( DefaultInstrumentManager.INSTRUMENT_TYPE_VALUE );
2034                }
2035                else
2036                {
2037                    throw new ServiceException( fullInstrumentName, "Encountered an unknown "
2038                        + "Instrument type for the Instrument with key, "
2039                        + fullInstrumentName + ": " + instrument.getClass().getName() );
2040                }
2041
2042                // Mark the instrument proxy as registered.
2043
proxy.setRegistered();
2044                
2045                // Store a reference to the proxy in the Instrument.
2046
( (AbstractInstrument)instrument ).setInstrumentProxy( proxy );
2047
2048                instrumentableProxy.addInstrumentProxy( proxy );
2049            }
2050            else
2051            {
2052                // Register the existing proxy with the Instrument. Make sure that the
2053
// type didn't change on us.
2054
if( instrument instanceof CounterInstrument )
2055                {
2056                    switch( proxy.getType() )
2057                    {
2058                        case DefaultInstrumentManager.INSTRUMENT_TYPE_COUNTER:
2059                            // Type is the same.
2060
// Store a reference to the proxy in the Instrument.
2061
( (AbstractInstrument)instrument ).setInstrumentProxy( proxy );
2062                            break;
2063
2064                        case DefaultInstrumentManager.INSTRUMENT_TYPE_NONE:
2065                            // Not yet set. Created in configuration.
2066
proxy.setType( DefaultInstrumentManager.INSTRUMENT_TYPE_COUNTER );
2067
2068                            // Store a reference to the proxy in the Instrument.
2069
( (AbstractInstrument)instrument ).setInstrumentProxy( proxy );
2070                            break;
2071
2072                        default:
2073                            throw new ServiceException( instrumentName,
2074                                "Instruments of more than one type are assigned to name: "
2075                                + instrumentName );
2076                    }
2077                }
2078                else if( instrument instanceof ValueInstrument )
2079                {
2080                    switch( proxy.getType() )
2081                    {
2082                        case DefaultInstrumentManager.INSTRUMENT_TYPE_VALUE:
2083                            // Type is the same.
2084
// Store a reference to the proxy in the Instrument.
2085
( (AbstractInstrument)instrument ).setInstrumentProxy( proxy );
2086                            break;
2087
2088                        case DefaultInstrumentManager.INSTRUMENT_TYPE_NONE:
2089                            // Not yet set. Created in configuration.
2090
proxy.setType( DefaultInstrumentManager.INSTRUMENT_TYPE_VALUE );
2091
2092                            // Store a reference to the proxy in the Instrument.
2093
( (AbstractInstrument)instrument ).setInstrumentProxy( proxy );
2094                            break;
2095
2096                        default:
2097                            throw new ServiceException( instrumentName,
2098                                "Instruments of more than one type are assigned to name: "
2099                                + instrumentName );
2100                    }
2101                }
2102                else
2103                {
2104                    throw new ServiceException( instrumentName, "Encountered an unknown Instrument "
2105                        + "type for the Instrument with name, " + instrumentName + ": "
2106                        + instrument.getClass().getName() );
2107                }
2108                
2109                // Mark the instrument proxy as registered.
2110
proxy.setRegistered();
2111            }
2112        }
2113
2114        // Loop over the child Instrumentables published by this Instrumentable
2115
Instrumentable[] children = instrumentable.getChildInstrumentables();
2116        for ( int i = 0; i < children.length; i++ )
2117        {
2118            Instrumentable child = children[i];
2119            
2120            // Make sure that the child instrumentable name is set.
2121
String JavaDoc childName = child.getInstrumentableName();
2122            if( childName == null )
2123            {
2124                String JavaDoc msg = "The getInstrumentableName() method of a child Instrumentable of " +
2125                    instrumentableName + " returned null. Child class: " +
2126                    child.getClass().getName();
2127                getLogger().debug( msg );
2128                throw new ServiceException( instrumentable.getClass().getName(), msg );
2129            }
2130            
2131            String JavaDoc fullChildName = instrumentableName + "." + childName;
2132            
2133            getLogger().debug( "Registering Child Instrumentable: " + fullChildName );
2134            
2135            // See if a proxy exists for the child Instrumentable yet.
2136
InstrumentableProxy proxy =
2137                instrumentableProxy.getChildInstrumentableProxy( fullChildName );
2138            if( proxy == null )
2139            {
2140                proxy = new InstrumentableProxy(
2141                    this, instrumentableProxy, fullChildName, childName );
2142                proxy.enableLogging( getLogger() );
2143                incrementInstrumentableCount();
2144                
2145                instrumentableProxy.addChildInstrumentableProxy( proxy );
2146            }
2147            
2148            // Recurse to the child
2149
registerInstrumentableInner( child, proxy, fullChildName );
2150        }
2151    }
2152}
2153
2154
Popular Tags