KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > appserv > management > client > ProxyFactory


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23 package com.sun.appserv.management.client;
24
25 import java.util.Collection JavaDoc;
26 import java.util.Set JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Map JavaDoc;
31 import java.util.HashMap JavaDoc;
32 import java.util.Collections JavaDoc;
33 import java.util.logging.Logger JavaDoc;
34 import java.io.IOException JavaDoc;
35 import java.lang.reflect.Proxy JavaDoc;
36
37 import javax.management.MBeanServerConnection JavaDoc;
38 import javax.management.InstanceNotFoundException JavaDoc;
39 import javax.management.ObjectName JavaDoc;
40 import javax.management.MBeanServer JavaDoc;
41 import javax.management.MalformedObjectNameException JavaDoc;
42 import javax.management.JMException JavaDoc;
43 import javax.management.relation.MBeanServerNotificationFilter JavaDoc;
44 import javax.management.MBeanServerNotification JavaDoc;
45 import javax.management.Notification JavaDoc;
46 import javax.management.NotificationListener JavaDoc;
47 import javax.management.remote.JMXConnector JavaDoc;
48 import javax.management.remote.JMXConnectionNotification JavaDoc;
49
50 import com.sun.appserv.management.DomainRoot;
51 import com.sun.appserv.management.base.AMX;
52 import com.sun.appserv.management.base.AMXAttributes;
53 import com.sun.appserv.management.base.XTypes;
54 import com.sun.appserv.management.base.Util;
55 import com.sun.appserv.management.util.jmx.MBeanProxyHandler;
56 import com.sun.appserv.management.util.jmx.MBeanServerConnectionSource;
57 import com.sun.appserv.management.util.jmx.MBeanServerConnectionConnectionSource;
58 import com.sun.appserv.management.util.misc.ClassUtil;
59 import com.sun.appserv.management.util.misc.TypeCast;
60
61 import com.sun.appserv.management.client.ConnectionSource;
62 import com.sun.appserv.management.client.handler.ConverterHandlerFactory;
63 import com.sun.appserv.management.client.handler.ConverterHandlerUtil;
64 import com.sun.appserv.management.client.handler.ProxyCache;
65
66 import com.sun.appserv.management.util.misc.GSetUtil;
67 import com.sun.appserv.management.util.misc.ExceptionUtil;
68 import com.sun.appserv.management.util.jmx.JMXUtil;
69 import com.sun.appserv.management.base.AMXClientLogger;
70
71 /**
72     Factory for {@link AMX} proxies.
73     Usually proxies are obtained by starting with the DomainRoot obtained via
74     {@link AppserverConnectionSource#getDomainRoot}.
75     
76     @see com.sun.appserv.management.client.AppserverConnectionSource
77  */

78 public final class ProxyFactory implements NotificationListener JavaDoc
79 {
80     private final ProxyCache mProxyCache;
81     private final ConnectionSource mConnectionSource;
82     private final ObjectName JavaDoc mDomainRootObjectName;
83     private final DomainRoot mDomainRoot;
84     private final String JavaDoc mMBeanServerID;
85     
86     private static final Map JavaDoc<MBeanServerConnection JavaDoc,ProxyFactory> INSTANCES =
87         Collections.synchronizedMap( new HashMap JavaDoc<MBeanServerConnection JavaDoc,ProxyFactory>() );
88     
89     
90         private
91     ProxyFactory( final ConnectionSource connSource )
92     {
93         assert( connSource != null );
94         
95         mConnectionSource = connSource;
96         mProxyCache = new ProxyCache();
97         
98         try
99         {
100             final MBeanServerConnection JavaDoc conn = getConnection();
101             
102             mMBeanServerID = JMXUtil.getMBeanServerID( conn );
103                 
104             mDomainRootObjectName = initDomainRootObjectName();
105             mDomainRoot = initDomainRoot();
106             
107             // we should always be able to listen to MBeans--
108
// but the http connector does not support listeners
109
try
110             {
111                 final MBeanServerNotificationFilter JavaDoc filter =
112                     new MBeanServerNotificationFilter JavaDoc();
113                 filter.enableAllObjectNames();
114                 filter.disableAllTypes();
115                 filter.enableType( MBeanServerNotification.UNREGISTRATION_NOTIFICATION );
116                 
117                 JMXUtil.listenToMBeanServerDelegate( conn, this, filter, null );
118             }
119             catch( Exception JavaDoc e )
120             {
121                 getLogger().warning( "ProxyFactory: connection does not support notifications: " +
122                     connSource.toString() );
123             }
124             
125             // same idea as above, this time we want to listen to connection died
126
// plus there may not be a JMXConnector involved
127
final JMXConnector JavaDoc connector = connSource.getJMXConnector( false );
128             if ( connector != null )
129             {
130                 try
131                 {
132                     connector.addConnectionNotificationListener( this, null, null );
133                 }
134                 catch( Exception JavaDoc e )
135                 {
136                     getLogger().warning(
137                         "ProxyFactory: connector does not support addConnectionNotificationListener: " +
138                         connSource );
139                 }
140             }
141         }
142         catch( Exception JavaDoc e )
143         {
144             getLogger().throwing( getClass().getName(), "ProxyFactory", e );
145             throw new RuntimeException JavaDoc( e );
146         }
147     }
148     
149     
150     /**
151         The connection is bad. Tell each proxy its gone and remove it.
152      */

153         private void
154     connectionBad()
155     {
156         synchronized( mProxyCache )
157         {
158             final Set JavaDoc<ObjectName JavaDoc> keySet = mProxyCache.keySet();
159             for( final ObjectName JavaDoc key : keySet )
160             {
161                 final AMX proxy = mProxyCache.getCachedProxy( key );
162                 
163                 mProxyCache.remove( Util.getObjectName( proxy ) );
164                 ConverterHandlerUtil.connectionBad( proxy );
165             }
166         }
167     }
168     
169     /**
170         Verify that the connection is still alive.
171      */

172         public boolean
173     checkConnection()
174     {
175         boolean connectionGood = true;
176         
177         try
178         {
179             getConnection().isRegistered( JMXUtil.getMBeanServerDelegateObjectName() );
180             connectionGood = true;
181         }
182         catch( Exception JavaDoc e )
183         {
184             connectionBad();
185         }
186         
187         return( connectionGood );
188     }
189     
190
191         void
192     notifsLost()
193     {
194         // should probably check each proxy for validity, but not clear if it's important...
195
}
196     
197     /**
198         Listens for MBeanServerNotification.UNREGISTRATION_NOTIFICATION and
199         JMXConnectionNotification and takes appropriate action.
200         <br>
201         Used internally as callback for {@link javax.management.NotificationListener}.
202         <b>DO NOT CALL THIS METHOD</b>.
203      */

204         public void
205     handleNotification(
206         final Notification JavaDoc notifIn,
207         final Object JavaDoc handback)
208     {
209         final String JavaDoc type = notifIn.getType();
210         
211         if ( type.equals( MBeanServerNotification.UNREGISTRATION_NOTIFICATION) )
212         {
213             final MBeanServerNotification JavaDoc notif = (MBeanServerNotification JavaDoc)notifIn;
214             final ObjectName JavaDoc objectName = notif.getMBeanName();
215             final AMX proxy = getProxy( objectName, AMX.class, false );
216             mProxyCache.remove( objectName );
217             ConverterHandlerUtil.targetUnregistered(proxy);
218             
219             getLogger().fine( "ProxyFactory.handleNotification: UNREGISTERED: " + objectName );
220         }
221         else if ( notifIn instanceof JMXConnectionNotification JavaDoc )
222         {
223             if ( type.equals( JMXConnectionNotification.CLOSED ) ||
224                 type.equals( JMXConnectionNotification.FAILED ) )
225             {
226                 connectionBad();
227             }
228             else if ( type.equals( JMXConnectionNotification.NOTIFS_LOST ) )
229             {
230                 notifsLost();
231             }
232         }
233         else
234         {
235             getLogger().fine( "ProxyFactory.handleNotification: UNKNOWN notif: " + type );
236         }
237     }
238     
239         private static Logger JavaDoc
240     getLogger()
241     {
242         return( AMXClientLogger.getInstance() );
243     }
244     
245         private ObjectName JavaDoc
246     initDomainRootObjectName()
247         throws IOException JavaDoc
248     {
249         final MBeanServerConnection JavaDoc conn = mConnectionSource.getMBeanServerConnection( false );
250         
251         final String JavaDoc patternString = "*:" +
252                             AMX.J2EE_TYPE_KEY + "=" + XTypes.DOMAIN_ROOT + ",*";
253         
254         ObjectName JavaDoc pattern = null;
255         try
256         {
257             pattern = new ObjectName JavaDoc( patternString );
258         }
259         catch ( MalformedObjectNameException JavaDoc e )
260         {
261             assert( false ); // can't happen
262
throw new RuntimeException JavaDoc( e );
263         }
264         
265         final Set JavaDoc<ObjectName JavaDoc> objectNames = JMXUtil.queryNames( conn, pattern, null );
266         if ( objectNames.size() != 1 )
267         {
268             throw new IllegalArgumentException JavaDoc( "Can't find DomainRoot MBean using pattern " + pattern );
269         }
270
271         final ObjectName JavaDoc objectName = GSetUtil.getSingleton( objectNames );
272         
273         return( objectName );
274     }
275     
276     private final static String JavaDoc DOMAIN_ROOT_KEY = "DomainRoot";
277     
278         public DomainRoot
279     createDomainRoot( )
280         throws IOException JavaDoc
281     {
282         return( mDomainRoot );
283     }
284     
285         public DomainRoot
286     initDomainRoot( )
287         throws IOException JavaDoc
288     {
289         final ObjectName JavaDoc domainRootObjectName = getDomainRootObjectName( );
290         
291         final DomainRoot domainRoot = (DomainRoot)
292             newProxyInstance(
293                 domainRootObjectName,
294                 new Class JavaDoc[] { DomainRoot.class } );
295         
296         return( domainRoot );
297     }
298     
299     /**
300         Return the DomainRoot. AMX may not yet be fully
301         initialized; call getDomainRoot( true ) if AMX
302         must be initialized upon return.
303         
304         @return the DomainRoot for this factory.
305      */

306         public DomainRoot
307     getDomainRoot( )
308     {
309         return getDomainRoot( false );
310     }
311     
312     /**
313         If 'waitReady' is true, then upon return AMX
314         is guaranteed to be fully loaded. Otherwise
315         AMX MBeans may continue to initialize asynchronously.
316         
317         @param waitReady
318         @return the DomainRoot for this factory.
319      */

320         public DomainRoot
321     getDomainRoot( boolean waitReady )
322     {
323         if ( waitReady )
324         {
325             mDomainRoot.waitAMXReady();
326         }
327         
328         return( mDomainRoot );
329     }
330     
331     
332     /**
333         @return the ConnectionSource used by this factory
334      */

335         public ConnectionSource
336     getConnectionSource()
337     {
338         return( mConnectionSource );
339     }
340     
341     /**
342         @return the JMX MBeanServerID for the MBeanServer in which MBeans reside.
343      */

344         public String JavaDoc
345     getMBeanServerID()
346     {
347         return( mMBeanServerID );
348     }
349     
350     /**
351         Return the ObjectName for the DomainMBean.
352      */

353         public ObjectName JavaDoc
354     getDomainRootObjectName()
355         throws IOException JavaDoc
356     {
357         return( mDomainRootObjectName );
358     }
359     
360     /**
361         Get an instance of the ProxyFactory for the MBeanServer. Generally
362         not applicable for remote clients.
363         
364         @param server
365      */

366         public static ProxyFactory
367     getInstance( final MBeanServer JavaDoc server )
368     {
369         return( getInstance( new MBeanServerConnectionSource( server ), true ) );
370     }
371     
372     /**
373         Get an instance of the ProxyFactory for the MBeanServerConnection.
374         Creates a ConnectionSource for it and calls getInstance( connSource, true ).
375      */

376         public static ProxyFactory
377     getInstance( final MBeanServerConnection JavaDoc conn )
378     {
379         return( getInstance( new MBeanServerConnectionConnectionSource( conn ), true ) );
380     }
381     
382     /**
383         Calls getInstance( connSource, true ).
384      */

385         public static ProxyFactory
386     getInstance( final ConnectionSource conn )
387     {
388         return( getInstance( conn, true ) );
389     }
390     
391     /**
392         Get an instance. If 'useMBeanServerID' is false, and
393         the ConnectionSource is not one that has been passed before, a new ProxyFactory
394         is instantiated which will not share its proxies with any previously-instantiated
395         ones. Such usage is discouraged, as it duplicates proxies. Pass 'true' unless
396         there is an excellent reason to pass 'false'.
397         
398         @param connSource the ConnectionSource
399         @param useMBeanServerID use the MBeanServerID to determine if it's the same server
400      */

401         public static synchronized ProxyFactory
402     getInstance(
403         final ConnectionSource connSource,
404         final boolean useMBeanServerID )
405     {
406         ProxyFactory instance = findInstance( connSource );
407         
408         if ( instance == null )
409         {
410             try
411             {
412                 // match based on the MBeanServerConnection; different
413
// ConnectionSource instances could wrap the same connection
414
final MBeanServerConnection JavaDoc conn =
415                     connSource.getMBeanServerConnection( false );
416                 
417                 instance = findInstance( conn );
418                 
419                 // if not found, match based on MBeanServerID as requested, or if this
420
// is an in-process MBeanServer
421
if ( instance == null &&
422                     ( useMBeanServerID || connSource instanceof MBeanServerConnectionSource ) )
423                 {
424                     final String JavaDoc id = JMXUtil.getMBeanServerID( conn );
425                     instance = findInstanceByID( id );
426                 }
427             
428                 if ( instance == null )
429                 {
430                     instance = new ProxyFactory( connSource );
431                     INSTANCES.put( conn, instance );
432                     
433                     getLogger().fine( "\n----------------\n" +
434                         "ProxyFactory.getInstance: created new factory for: " +
435                             instance.getMBeanServerID() +
436                         "\n----------------\n" );
437                 }
438             }
439             catch( Exception JavaDoc e )
440             {
441                 getLogger().severe( "ProxyFactory.getInstance: " +
442                     "Failure trying to create a new ProxyFactory: " + ExceptionUtil.toString( e ) );
443                 throw new RuntimeException JavaDoc( e );
444             }
445         }
446         
447         return( instance );
448     }
449     
450     /**
451         @return ProxyFactory corresponding to the ConnectionSource
452      */

453         public static synchronized ProxyFactory
454     findInstance( final ConnectionSource conn )
455     {
456         return( INSTANCES.get( conn ) );
457     }
458     
459     /**
460         @return ProxyFactory corresponding to the MBeanServerConnection
461      */

462         public static synchronized ProxyFactory
463     findInstance( final MBeanServerConnection JavaDoc conn )
464     {
465         ProxyFactory instance = null;
466         
467         final Collection JavaDoc<ProxyFactory> values = INSTANCES.values();
468         for( final ProxyFactory factory : values )
469         {
470             if ( factory.getConnectionSource().getExistingMBeanServerConnection( ) == conn )
471             {
472                 instance = factory;
473                 break;
474             }
475         }
476         return( instance );
477     }
478     
479     
480     /**
481         @return ProxyFactory corresponding to the MBeanServerID
482      */

483         public static synchronized ProxyFactory
484     findInstanceByID( final String JavaDoc mbeanServerID )
485     {
486         ProxyFactory instance = null;
487         
488         final Collection JavaDoc<ProxyFactory> values = INSTANCES.values();
489         for( final ProxyFactory factory : values )
490         {
491             if ( factory.getMBeanServerID().equals( mbeanServerID ) )
492             {
493                 instance = factory;
494                 break;
495             }
496         }
497         
498         return( instance );
499     }
500     
501     
502     /**
503         @return an appropriate {@link AMX} interface for the ObjectName
504         @deprecated use versions that take a class as a parameter
505      */

506         public AMX
507     getProxy( final ObjectName JavaDoc objectName )
508     {
509         return getProxy( objectName, true );
510     }
511         
512     /**
513         Get any existing proxy, returning null if none exists and 'create' is false.
514         
515         @param objectName ObjectName for which a proxy should be created
516         @param create true to create the proxy, false to return existing value
517         @return an appropriate {@link AMX} interface for the ObjectName
518         @deprecated use versions that take a class as a parameter
519      */

520         public AMX
521     getProxy( final ObjectName JavaDoc objectName, boolean create )
522     {
523         return getProxy( objectName, AMX.class, create );
524     }
525     
526     /**
527         The actual interface(s) that the proxy implements are predetermined.
528         Specifying the interface ties the return type to the interface at compile-time
529         but has no effect on the actual interfaces that are implemented by
530         the proxy.
531         @return an appropriate {@link AMX} interface for the ObjectName
532      */

533         public synchronized <T extends AMX> T
534     getProxy(
535         final ObjectName JavaDoc objectName,
536         final Class JavaDoc<T> theInterface )
537     {
538         return getProxy( objectName, theInterface, true );
539     }
540     
541     /**
542         Get any existing proxy, returning null if none exists and 'create' is false.
543         
544         @param objectName ObjectName for which a proxy should be created
545         @param create true to create the proxy, false to return existing value
546         @param theClass class of returned proxy, avoids casts and compiler warnings
547         @return an appropriate {@link AMX} interface for the ObjectName
548      */

549         public synchronized <T extends AMX> T
550     getProxy(
551         final ObjectName JavaDoc objectName,
552         Class JavaDoc<T> theClass,
553         boolean create )
554     {
555         AMX proxy = mProxyCache.getCachedProxy( objectName );
556         
557         if ( proxy == null && create )
558         {
559             proxy = createProxy( objectName );
560         }
561         return theClass.cast( proxy );
562     }
563     
564     /**
565         @return MBeanServerConnection used by this factory
566      */

567         protected MBeanServerConnection JavaDoc
568     getConnection()
569         throws IOException JavaDoc
570     {
571         return( getConnectionSource().getMBeanServerConnection( false ) );
572     }
573     
574     /**
575         Create a new proxy. When a new proxy is created, its parent is
576         required, which could cause a chain of proxies to be created.
577         @param ObjectName
578      */

579         private AMX
580     createProxy( final ObjectName JavaDoc objectName )
581     {
582         AMX proxy = null;
583         
584         try
585         {
586             String JavaDoc proxyInterfaceName = null;
587             Class JavaDoc proxyInterface = null;
588             
589             proxyInterfaceName = (String JavaDoc)
590                 getConnection().getAttribute( objectName, AMXAttributes.ATTR_INTERFACE_NAME );
591             
592             proxyInterface = ClassUtil.getClassFromName( proxyInterfaceName );
593                     
594             proxy = newProxyInstance( objectName, new Class JavaDoc[] { proxyInterface } );
595         }
596         catch( IllegalArgumentException JavaDoc e )
597         {
598             throw e;
599         }
600         catch( Exception JavaDoc e )
601         {
602             throw new RuntimeException JavaDoc( e );
603         }
604                 
605         return( proxy );
606     }
607     
608         private MBeanProxyHandler
609     createProxyHandler( final ObjectName JavaDoc objectName )
610         throws IOException JavaDoc
611     {
612         return ConverterHandlerFactory.createHandler( mConnectionSource, objectName );
613     }
614
615         
616     /**
617         Instantiates a new proxy using the default AttributeNameMangler and with any desired number
618         of interfaces. If you want NotificationBroadcaster as one of the interfaces, you must
619         supply it in the list.
620         Use of this routine is discouraged in favor of
621         {@link #getProxy}
622         
623         @param objectName the target MBean which will be invoked by the proxy
624         @param interfaceClasses all interfaces the proxy should implement
625         
626         @return the new Proxy implementing the specified interface
627      */

628         public AMX
629     newProxyInstance(
630         final ObjectName JavaDoc objectName,
631         final Class JavaDoc<?>[] interfaceClasses )
632         throws IOException JavaDoc
633     {
634         final MBeanProxyHandler handler = createProxyHandler( objectName );
635         
636         final ClassLoader JavaDoc classLoader = interfaceClasses[ 0 ].getClassLoader();
637         
638         final AMX proxy = Util.asAMX(Proxy.newProxyInstance( classLoader, interfaceClasses, handler));
639         if ( proxy != null )
640         {
641             mProxyCache.remove( objectName );
642             mProxyCache.cacheProxy( proxy );
643         }
644         
645         return( proxy );
646     }
647     
648         protected static String JavaDoc
649     toString( final Object JavaDoc o )
650     {
651         return( com.sun.appserv.management.util.stringifier.SmartStringifier.toString( o ) );
652     }
653     
654     
655     /**
656         Convert a Set of ObjectName to a Set of AMX.
657         
658         @return a Set of AMX from a Set of ObjectName.
659      */

660         public Set JavaDoc<AMX>
661     toProxySet( final Set JavaDoc<ObjectName JavaDoc> objectNames )
662     {
663         final Set JavaDoc<AMX> s = new HashSet JavaDoc<AMX>();
664         
665         for( final ObjectName JavaDoc objectName : objectNames )
666         {
667             try
668             {
669                 final AMX proxy = getProxy( objectName, AMX.class, true );
670                 assert( ! s.contains( proxy ) );
671                 s.add( proxy );
672             }
673             catch( Exception JavaDoc e )
674             {
675                 final Throwable JavaDoc rootCause = ExceptionUtil.getRootCause( e );
676                 
677                 //getLogger
678
System.out.println( "ProxyFactory.toProxySet: exception for MBean " +
679                     objectName + " = " + rootCause );
680             }
681         }
682         
683         return( s );
684     }
685     
686     /**
687         Convert a Collection of ObjectName to a List of AMX.
688         
689         @return a List of AMX from a List of ObjectName.
690      */

691         public List JavaDoc<AMX>
692     toProxyList( final Collection JavaDoc<ObjectName JavaDoc> objectNames )
693     {
694         final List JavaDoc<AMX> list = new ArrayList JavaDoc<AMX>();
695         
696         for( final ObjectName JavaDoc objectName : objectNames )
697         {
698             try
699             {
700                 final AMX proxy = getProxy( objectName, AMX.class, true );
701                 list.add( proxy );
702             }
703             catch( Exception JavaDoc e )
704             {
705                 final Throwable JavaDoc rootCause = ExceptionUtil.getRootCause( e );
706                 
707                 //getLogger
708
System.out.println( "ProxyFactory.toProxyList: exception for MBean " +
709                     objectName + " = " + rootCause );
710             }
711         }
712         
713         return( list );
714     }
715     
716     /**
717         Convert a Map of ObjectName, and convert it to a Map
718         of AMX, with the same keys.
719         
720         @return a Map of AMX from a Map of ObjectName.
721      */

722         public Map JavaDoc<String JavaDoc,AMX>
723     toProxyMap(
724         final Map JavaDoc<String JavaDoc,ObjectName JavaDoc> objectNameMap )
725     {
726         final Map JavaDoc<String JavaDoc,AMX> resultMap = new HashMap JavaDoc<String JavaDoc,AMX>();
727         
728         final Set JavaDoc<String JavaDoc> keys = objectNameMap.keySet();
729         
730         for( final String JavaDoc key : keys )
731         {
732             final ObjectName JavaDoc objectName = objectNameMap.get( key );
733             
734             try
735             {
736                 final AMX proxy = getProxy( objectName, AMX.class, true );
737                 resultMap.put( key, proxy );
738             }
739             catch( Exception JavaDoc e )
740             {
741                 final Throwable JavaDoc rootCause = ExceptionUtil.getRootCause( e );
742                 
743                 System.out.println( "ProxyFactory.toProxyMap: exception for MBean " +
744                     objectName + " = " + rootCause );
745             }
746         }
747         
748         return( resultMap );
749     }
750     
751 }
752
753
754
755
756
757
758
759
760
761
762
763
Popular Tags