KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > appserv > management > util > jmx > MBeanProxyHandler


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  
24 /*
25  * $Header: /cvs/glassfish/admin-core/mbeanapi/src/java/com/sun/appserv/management/util/jmx/MBeanProxyHandler.java,v 1.6 2005/12/25 03:51:24 tcfujii Exp $
26  * $Revision: 1.6 $
27  * $Date: 2005/12/25 03:51:24 $
28  */

29
30 package com.sun.appserv.management.util.jmx;
31
32 import java.io.IOException JavaDoc;
33
34 import java.lang.reflect.Proxy JavaDoc;
35 import java.lang.reflect.Method JavaDoc;
36 import java.util.logging.Logger JavaDoc;
37
38 import javax.management.Attribute JavaDoc;
39 import javax.management.AttributeList JavaDoc;
40 import javax.management.MBeanAttributeInfo JavaDoc;
41 import javax.management.MBeanInfo JavaDoc;
42 import javax.management.MBeanServerConnection JavaDoc;
43 import javax.management.ObjectName JavaDoc;
44 import javax.management.MBeanServerInvocationHandler JavaDoc;
45 import javax.management.NotificationBroadcaster JavaDoc;
46 import javax.management.ReflectionException JavaDoc;
47 import javax.management.IntrospectionException JavaDoc;
48 import javax.management.InstanceNotFoundException JavaDoc;
49 import javax.management.AttributeNotFoundException JavaDoc;
50 import javax.management.InvalidAttributeValueException JavaDoc;
51 import javax.management.MBeanException JavaDoc;
52
53
54 import com.sun.appserv.management.base.AMXDebug;
55 import com.sun.appserv.management.client.ConnectionSource;
56 import com.sun.appserv.management.util.jmx.JMXUtil;
57 import com.sun.appserv.management.util.jmx.AttributeNameMangler;
58 import com.sun.appserv.management.util.jmx.AttributeNameMapper;
59 import com.sun.appserv.management.util.jmx.AttributeNameMapperImpl;
60 import com.sun.appserv.management.util.misc.ExceptionUtil;
61 import com.sun.appserv.management.util.misc.StringUtil;
62 import com.sun.appserv.management.util.misc.ObjectUtil;
63 import com.sun.appserv.management.util.misc.Output;
64
65
66 /**
67     Implementation of a proxy <i>handler</i> that supports Attribute names which are not legal
68     Java identifiers. It does so by mapping illegal Java identifiers into legal
69     names. Any interface supplied needs to take mapped names into account.
70     <p>
71     Allows specification of either an AttributeNameMangler or AttributeNameMapper for maximum
72     flexibility in how illegal Attribute names are mapped.
73  */

74 public class MBeanProxyHandler extends MBeanServerInvocationHandler JavaDoc
75     // implements MBeanProxyHandlerIntf
76
{
77     protected final static String JavaDoc GET = "get";
78     protected final static String JavaDoc SET = "set";
79     protected final static String JavaDoc IS = "is";
80     protected final static int GET_PREFIX_LENGTH = GET.length();
81     protected final static int IS_PREFIX_LENGTH = IS.length();
82     
83     protected final ConnectionSource mConnectionSource;
84     protected AttributeNameMangler mMangler;
85     private AttributeNameMapper mMapper;
86     private final ObjectName JavaDoc mTargetObjectName;
87     private boolean mCacheMBeanInfo;
88     private MBeanInfo JavaDoc mCachedMBeanInfo;
89     private boolean mMBeanInfoIsInvariant = false;
90     private Logger JavaDoc mLogger;
91     private boolean mTargetValid;
92     private final Integer JavaDoc mHashCode;
93     
94     protected Output mDebug;
95     
96     
97     static protected final String JavaDoc DEBUG_ID =
98         "com.sun.appserv.management.util.jmx.MBeanProxyHandler";
99     
100         public int
101     hashCode()
102     {
103         return ObjectUtil.hashCode( mTargetObjectName,
104                 mConnectionSource, mLogger, mMangler, mMapper, mCachedMBeanInfo, mDebug) ^
105             ObjectUtil.hashCode( mCacheMBeanInfo ) ^
106             ObjectUtil.hashCode( mMBeanInfoIsInvariant ) ^
107             ObjectUtil.hashCode( mTargetValid );
108     }
109     
110         public boolean
111     equals( final Object JavaDoc rhs )
112     {
113         if ( rhs == this )
114         {
115             return true;
116         }
117         
118         final MBeanProxyHandler other = (MBeanProxyHandler)rhs;
119         
120         boolean equals = mTargetObjectName.equals( other.getTargetObjectName() );
121         if ( equals )
122         {
123             try
124             {
125                 equals = getConnection() == other.getConnection();
126             }
127             catch( Exception JavaDoc e )
128             {
129                 equals = false;
130             }
131         }
132         
133         return equals;
134     }
135     
136     
137         protected String JavaDoc
138     getDebugID()
139     {
140         return DEBUG_ID;
141     }
142     
143     /**
144         Normally created through MBeanProxyFactory.newProxyInstance(). Creates a new instance to be used
145         as a <i>handler<i> object for Proxy.newProxyInstance.
146         
147         @param connectionSource the connection
148         @param objectName the ObjectName of the proxied MBean
149      */

150         public
151     MBeanProxyHandler(
152         ConnectionSource connectionSource,
153         ObjectName JavaDoc objectName )
154         throws IOException JavaDoc
155     {
156         this( connectionSource, objectName, (AttributeNameMangler)null );
157     }
158     
159         private
160     MBeanProxyHandler(
161         final ConnectionSource connectionSource,
162         final ObjectName JavaDoc objectName,
163         final AttributeNameMapper mapper,
164         final AttributeNameMangler mangler )
165         throws IOException JavaDoc
166     {
167         super( connectionSource.getMBeanServerConnection( false ), objectName );
168         
169         mDebug = AMXDebug.getInstance().getOutput( getDebugID() );
170         debugMethod( "MBeanProxyHandler", connectionSource, objectName, mapper, mangler );
171         mMangler = mangler;
172         mMapper = mapper;
173         mConnectionSource = connectionSource;
174         mTargetObjectName = objectName;
175         mTargetValid = true;
176         
177         mCacheMBeanInfo = true;
178         mCachedMBeanInfo = null;
179         mLogger = null;
180         
181         mHashCode = this.hashCode();
182     }
183     
184     
185         public final void
186     targetUnregistered()
187     {
188         debugMethod( mTargetObjectName.toString(), "targetUnregistered" );
189         mTargetValid = false;
190         assert( ! targetIsValid() );
191     }
192     
193         public final void
194     connectionBad()
195     {
196         debugMethod( "connectionBad" );
197         mTargetValid = false;
198         assert( ! targetIsValid() );
199     }
200     
201         protected final boolean
202     targetIsValid()
203     {
204         return( mTargetValid );
205     }
206     
207         public final boolean
208     checkValid()
209     {
210         if ( mTargetValid )
211         {
212             try
213             {
214                 mTargetValid = getConnection().isRegistered( getTargetObjectName() );
215             }
216             catch( Exception JavaDoc e )
217             {
218                 debug( "checkValid: connection failed" );
219                 mTargetValid = false;
220             }
221         }
222         return( mTargetValid );
223     }
224     
225     /**
226         Same as MBeanProxyHandler( connection, objectName ), but can take a name mangler.
227         
228         @param connectionSource the connection
229         @param objectName the ObjectName of the proxied MBean
230         @param mangler optional name mangler for illegal Attribute names
231      */

232         public
233     MBeanProxyHandler(
234         ConnectionSource connectionSource,
235         ObjectName JavaDoc objectName,
236         AttributeNameMangler mangler )
237         throws IOException JavaDoc
238     {
239         this( connectionSource, objectName, null, mangler );
240     }
241     
242     /**
243         Same as MBeanProxyHandler( connection, objectName ), but can take a supplied
244         mapper for illegal Attribute names.
245         
246         @param connectionSource the connection
247         @param objectName the ObjectName of the proxied MBean
248         @param mapper optional name mapper for illegal Attribute names
249      */

250         public
251     MBeanProxyHandler(
252         ConnectionSource connectionSource,
253         ObjectName JavaDoc objectName,
254         AttributeNameMapper mapper )
255         throws IOException JavaDoc
256     {
257         this( connectionSource, objectName, mapper, null );
258     }
259     
260         public void
261     setProxyLogger( final Logger JavaDoc logger )
262     {
263         mLogger = logger;
264     }
265     
266     protected final static String JavaDoc LOGGER_NAME = "com.sun.appserv.management.Proxy";
267     
268         public Logger JavaDoc
269     getProxyLogger( )
270     {
271         if ( mLogger == null )
272         {
273             mLogger = Logger.getLogger( this.getClass().getName() );
274         }
275         return( mLogger );
276     }
277     
278         public final ConnectionSource
279     getConnectionSource()
280     {
281         return( mConnectionSource );
282     }
283     
284         protected final MBeanServerConnection JavaDoc
285     getConnection()
286         throws IOException JavaDoc
287     {
288         return( mConnectionSource.getMBeanServerConnection( false ) );
289     }
290     
291         protected final ObjectName JavaDoc
292     getTargetObjectName()
293     {
294         return( mTargetObjectName );
295     }
296
297         public static String JavaDoc[]
298     getAllAttributeNames(
299         final MBeanAttributeInfo JavaDoc[] infos )
300     {
301         return( JMXUtil.getAttributeNames( infos ) );
302     }
303     
304     /**
305         Create a mapper based on the supplied attributeInfos
306         
307         @param attributeInfos
308         @param mangler
309         @return AttributeNameMapper
310      */

311         AttributeNameMapper
312     createMapper(
313         final MBeanAttributeInfo JavaDoc[] attributeInfos,
314         final AttributeNameMangler mangler)
315     {
316         return( new AttributeNameMapperImpl( getAllAttributeNames( attributeInfos ), mangler ) );
317     }
318     
319     /**
320         Initialize a mapper based on the supplied attributeInfos. Does nothing if already
321         initialized.
322      */

323         protected void
324     initMapper( )
325         throws IOException JavaDoc, IntrospectionException JavaDoc, ReflectionException JavaDoc, InstanceNotFoundException JavaDoc
326     {
327         // lazy initialization here
328
if ( mMapper == null && mMangler != null)
329         {
330             final MBeanInfo JavaDoc mbeanInfo = getMBeanInfo( true );
331             
332             mMapper = createMapper( mbeanInfo.getAttributes(), mMangler);
333         }
334     }
335     
336         protected String JavaDoc
337     extractAttributeNameFromMethod( String JavaDoc methodName )
338     {
339         assert( methodName.startsWith( GET ) ||
340                 methodName.startsWith( SET ) ||
341                 methodName.startsWith( IS ) );
342         final int startIndex = methodName.startsWith( GET ) || methodName.startsWith( SET ) ?
343             GET_PREFIX_LENGTH : IS_PREFIX_LENGTH;
344         return( methodName.substring( startIndex, methodName.length() ) );
345     }
346     
347         protected boolean
348     isMappedAttributeMethod( final String JavaDoc attributeName )
349     {
350         boolean isMapped = false;
351         
352         if ( mMapper != null )
353         {
354             final String JavaDoc originalName = mMapper.derivedToOriginal( attributeName );
355             
356             isMapped = ! attributeName.equals( originalName );
357         }
358         
359         return( isMapped );
360     }
361     
362     
363         protected void
364     cacheMBeanInfo( final boolean cacheIt )
365     {
366         mCacheMBeanInfo = cacheIt;
367         mMBeanInfoIsInvariant = cacheIt;
368         if ( ! cacheIt )
369         {
370             mCachedMBeanInfo = null;
371         }
372     }
373     
374         public final boolean
375     getMBeanInfoIsInvariant()
376     {
377         return( mMBeanInfoIsInvariant );
378     }
379     
380         protected final void
381     setMBeanInfoIsInvariant( boolean isInvariant )
382     {
383         mMBeanInfoIsInvariant = isInvariant;
384     }
385     
386         protected final boolean
387     getCacheMBeanInfo()
388     {
389         return( mCacheMBeanInfo );
390     }
391     
392     /**
393         Same as XAttributesAccess.getAttributes, but with exceptions
394         
395         @param refresh whether to get a fresh copy
396      */

397         protected MBeanInfo JavaDoc
398     getMBeanInfo( boolean refresh )
399         throws IOException JavaDoc, InstanceNotFoundException JavaDoc, IntrospectionException JavaDoc, ReflectionException JavaDoc
400     {
401         if ( refresh ||
402             (! mCacheMBeanInfo) ||
403             mCachedMBeanInfo == null )
404         {
405             mCachedMBeanInfo = getConnection().getMBeanInfo( getTargetObjectName() );
406         }
407         return( mCachedMBeanInfo );
408     }
409     
410     /**
411         Same as XAttributesAccess.getAttribute, but with exceptions
412      */

413         public Object JavaDoc
414     getAttribute( final String JavaDoc attributeName )
415         throws InstanceNotFoundException JavaDoc, ReflectionException JavaDoc,
416         MBeanException JavaDoc, AttributeNotFoundException JavaDoc, IOException JavaDoc
417     {
418         final Object JavaDoc result =
419             getConnection().getAttribute( getTargetObjectName(), attributeName );
420             
421         postGetAttributeHook( attributeName, result );
422     
423         return( result );
424     }
425     
426     
427     /**
428         Same as XAttributesAccess.getAttributes, but with exceptions
429      */

430         public AttributeList JavaDoc
431     getAttributes( final String JavaDoc[] attrNames )
432         throws IOException JavaDoc, InstanceNotFoundException JavaDoc, ReflectionException JavaDoc
433     {
434         final AttributeList JavaDoc results =
435             getConnection().getAttributes( getTargetObjectName(), attrNames );
436             
437         postGetAttributesHook( attrNames, results );
438         
439         return( results );
440     }
441     
442     /**
443         Same as XAttributesAccess.setAttribute, but with exceptions
444      */

445         public void
446     setAttribute( final Attribute JavaDoc attr )
447         throws IOException JavaDoc, InstanceNotFoundException JavaDoc, ReflectionException JavaDoc,
448             AttributeNotFoundException JavaDoc, MBeanException JavaDoc, InvalidAttributeValueException JavaDoc
449     {
450         getConnection().setAttribute( getTargetObjectName(), attr );
451         
452         postSetAttributeHook( attr );
453     }
454     
455     /**
456         Same as XAttributesAccess.setAttributes, but with exceptions
457      */

458         public AttributeList JavaDoc
459     setAttributes( final AttributeList JavaDoc requested )
460         throws IOException JavaDoc, InstanceNotFoundException JavaDoc, ReflectionException JavaDoc
461     {
462         final AttributeList JavaDoc results = getConnection().setAttributes( getTargetObjectName(), requested );
463         
464         postSetAttributesHook( requested, results );
465                 
466         return( results );
467     }
468     
469     private final String JavaDoc LOG_LEVEL_NAME = "LogLevel";
470     
471         protected void
472     postGetAttributeHook(
473         final String JavaDoc name,
474         final Object JavaDoc value )
475     {
476     }
477     
478         protected void
479     postGetAttributesHook(
480         final String JavaDoc[] requested,
481         final AttributeList JavaDoc actual )
482     {
483     }
484     
485         protected void
486     postSetAttributeHook( final Attribute JavaDoc attr )
487     {
488     }
489     
490         protected void
491     postSetAttributesHook(
492         final AttributeList JavaDoc requested,
493         final AttributeList JavaDoc actual )
494     {
495     }
496     
497     
498     /**
499         Invoke the specified method. This implementation supports additional functionality
500         over the JMX MBeanServerInvocationHandler:
501         (1) It supports mapped Attribute names (ones that are not legal Java names)
502         (2) it supports XAttributesAccess, which otherwise does not work correctly
503         <p>
504         For anything else, the behavior of MBeanServerInvocationHandler is used.
505      */

506         public Object JavaDoc
507     invoke(
508         Object JavaDoc proxy,
509         Method JavaDoc method,
510         Object JavaDoc[] args
511         )
512         throws java.lang.Throwable JavaDoc
513     {
514         final String JavaDoc methodName = method.getName();
515         final int numArgs = args == null ? 0 : args.length;
516         
517         debugMethod( method.getName(), args );
518         
519         Object JavaDoc result = null;
520         
521         final boolean isGetter = JMXUtil.isIsOrGetter( method );
522         final boolean isSetter = isGetter ? false : JMXUtil.isSetter( method );
523         
524         boolean handled = false;
525         
526         if ( methodName.equals( "getTargetObjectName" ) )
527         {
528             handled = true;
529             result = getTargetObjectName();
530         }
531         else if ( methodName.equals( "getMBeanInfo" ) && numArgs <= 1)
532         {
533             handled = true;
534             
535             if ( numArgs == 1 )
536             {
537                 result = getMBeanInfo( ((Boolean JavaDoc)args[ 0 ] ).booleanValue() );
538             }
539             else if ( numArgs == 0 )
540             {
541                 result = getMBeanInfo( mCacheMBeanInfo );
542             }
543             else
544             {
545                 handled = false;
546             }
547         }
548         else if ( methodName.equals( "getProxyLogger" ) && numArgs == 0 )
549         {
550             handled = true;
551             result = getProxyLogger();
552         }
553         else if ( methodName.equals( "setProxyLogger" ) &&
554                     numArgs == 1 &&
555                     method.getParameterTypes()[ 0 ] == Logger JavaDoc.class )
556         {
557             handled = true;
558             setProxyLogger( (Logger JavaDoc)args[ 0 ] );
559         }
560         else if ( (isGetter || isSetter) )
561         {
562             handled = true;
563             // it's a plain getFoo(), setFoo( f ) call
564
initMapper( );
565             
566             final String JavaDoc javaName = extractAttributeNameFromMethod( methodName );
567
568             String JavaDoc attributeName = javaName;
569             
570             if ( isMappedAttributeMethod( javaName ) )
571             {
572                 attributeName = mMapper.derivedToOriginal( javaName );
573             }
574                 
575             //trace( "MBeanProxyHandler.invoke: mapped attribute: " + javaName + " => " + attributeName );
576

577             if ( isGetter )
578             {
579                 result = getAttribute( attributeName );
580             }
581             else
582             {
583                 final Attribute JavaDoc attr = new Attribute JavaDoc( attributeName, args[ 0 ] );
584                 setAttribute( attr );
585             }
586         }
587         else if ( methodName.indexOf( "etAttribute" ) == 1 )
588         {
589             handled = true;
590                 
591             // likely one of getAttribute(), getAttributes(), setAttribute(), setAttributes()
592

593             //p( "MBeanProxyHandler.invoke: " + method.getName() + " " + numArgs + " args." );
594
if ( JMXUtil.isGetAttribute( method ) )
595             {
596                 final String JavaDoc attrName = (String JavaDoc)args[ 0 ];
597                 result = getAttribute( attrName );
598             }
599             else if ( JMXUtil.isGetAttributes( method ) )
600             {
601                 final String JavaDoc[] attrNames = (String JavaDoc[])args[ 0 ];
602                 result = (AttributeList JavaDoc)getAttributes( attrNames );
603             }
604             else if ( JMXUtil.isSetAttribute( method ) )
605             {
606                 final Attribute JavaDoc attr = (Attribute JavaDoc)args[ 0 ];
607                 setAttribute( attr );
608             }
609             else if ( JMXUtil.isSetAttributes( method ) )
610             {
611                 final AttributeList JavaDoc requested = (AttributeList JavaDoc)args[ 0 ];
612                 result = (AttributeList JavaDoc)setAttributes( requested );
613             }
614             else
615             {
616                 handled = false;
617             }
618         }
619         else if ( methodName.equals( "hashCode" ) )
620         {
621             /*
622                 java.lang.reflect.Proxy will route all calls through invoke(),
623                 even hashCode(). To avoid newing up an Integer every time,
624                 just return a stored version. hashCode() is called frequently
625                 when proxies are inserted into Sets or Maps. toString() and
626                 equals() don't seem to get called however.
627              */

628             result = mHashCode;
629             handled = true;
630         }
631         else if ( methodName.equals( "toString" ) )
632         {
633             result = "proxy to " + JMXUtil.toString( getTargetObjectName() );
634             handled = true;
635         }
636         else if ( methodName.equals( "equals" ) && numArgs == 1)
637         {
638             result = this.equals( args[ 0 ] );
639             handled = true;
640         }
641         
642         if ( ! handled )
643         {
644             debugMethod( getTargetObjectName().toString(), "super.invoke",
645                 method.getName(), args );
646
647             result = super.invoke( proxy, method, args );
648         }
649             
650         return( result );
651     }
652
653         protected boolean
654     getDebug()
655     {
656         return AMXDebug.getInstance().getDebug( getDebugID() );
657     }
658    
659         protected void
660     debugMethod( final String JavaDoc methodName, final Object JavaDoc... args )
661     {
662         if ( getDebug() )
663         {
664             mDebug.println( AMXDebug.methodString( methodName, args ) );
665         }
666     }
667     
668         protected void
669     debugMethod(
670         final String JavaDoc msg,
671         final String JavaDoc methodName,
672         final Object JavaDoc... args )
673     {
674         if ( getDebug() )
675         {
676             mDebug.println( AMXDebug.methodString( methodName, args ) + ": " + msg );
677         }
678     }
679     
680         protected void
681     debug( final Object JavaDoc... args )
682     {
683         if ( getDebug() )
684         {
685             mDebug.println( StringUtil.toString( "", args) );
686         }
687     }
688     
689         protected void
690     debug( final Object JavaDoc o )
691     {
692         mDebug.println( o );
693     }
694 }
695
696
697
698
699
700
Popular Tags