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