1 /*
2  * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.jmx.mbeanserver;
27 
28 import static com.sun.jmx.mbeanserver.Util.*;
29 
30 import java.lang.reflect.Method;
31 import java.util.Map;
32 
33 import javax.management.Attribute;
34 import javax.management.MBeanServerConnection;
35 import javax.management.NotCompliantMBeanException;
36 import javax.management.ObjectName;
37 
38 /**
39    <p>Helper class for an {@link InvocationHandler} that forwards methods from an
40    MXBean interface to a named
41    MXBean in an MBean Server and handles translation between the
42    arbitrary Java types in the interface and the Open Types used
43    by the MXBean.</p>
44 
45    @since 1.6
46 */
47 public class MXBeanProxy {
MXBeanProxy(Class<?> mxbeanInterface)48     public MXBeanProxy(Class<?> mxbeanInterface) {
49 
50         if (mxbeanInterface == null)
51             throw new IllegalArgumentException("Null parameter");
52 
53         final MBeanAnalyzer<ConvertingMethod> analyzer;
54         try {
55             analyzer =
56                 MXBeanIntrospector.getInstance().getAnalyzer(mxbeanInterface);
57         } catch (NotCompliantMBeanException e) {
58             throw new IllegalArgumentException(e);
59         }
60         analyzer.visit(new Visitor());
61     }
62 
63     private class Visitor
64             implements MBeanAnalyzer.MBeanVisitor<ConvertingMethod> {
visitAttribute(String attributeName, ConvertingMethod getter, ConvertingMethod setter)65         public void visitAttribute(String attributeName,
66                                    ConvertingMethod getter,
67                                    ConvertingMethod setter) {
68             if (getter != null) {
69                 getter.checkCallToOpen();
70                 Method getterMethod = getter.getMethod();
71                 handlerMap.put(getterMethod,
72                                new GetHandler(attributeName, getter));
73             }
74             if (setter != null) {
75                 // return type is void, no need for checkCallToOpen
76                 Method setterMethod = setter.getMethod();
77                 handlerMap.put(setterMethod,
78                                new SetHandler(attributeName, setter));
79             }
80         }
81 
visitOperation(String operationName, ConvertingMethod operation)82         public void visitOperation(String operationName,
83                                    ConvertingMethod operation) {
84             operation.checkCallToOpen();
85             Method operationMethod = operation.getMethod();
86             String[] sig = operation.getOpenSignature();
87             handlerMap.put(operationMethod,
88                            new InvokeHandler(operationName, sig, operation));
89         }
90     }
91 
92     private static abstract class Handler {
Handler(String name, ConvertingMethod cm)93         Handler(String name, ConvertingMethod cm) {
94             this.name = name;
95             this.convertingMethod = cm;
96         }
97 
getName()98         String getName() {
99             return name;
100         }
101 
getConvertingMethod()102         ConvertingMethod getConvertingMethod() {
103             return convertingMethod;
104         }
105 
invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)106         abstract Object invoke(MBeanServerConnection mbsc,
107                                ObjectName name, Object[] args) throws Exception;
108 
109         private final String name;
110         private final ConvertingMethod convertingMethod;
111     }
112 
113     private static class GetHandler extends Handler {
GetHandler(String attributeName, ConvertingMethod cm)114         GetHandler(String attributeName, ConvertingMethod cm) {
115             super(attributeName, cm);
116         }
117 
118         @Override
invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)119         Object invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)
120                 throws Exception {
121             assert(args == null || args.length == 0);
122             return mbsc.getAttribute(name, getName());
123         }
124     }
125 
126     private static class SetHandler extends Handler {
SetHandler(String attributeName, ConvertingMethod cm)127         SetHandler(String attributeName, ConvertingMethod cm) {
128             super(attributeName, cm);
129         }
130 
131         @Override
invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)132         Object invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)
133                 throws Exception {
134             assert(args.length == 1);
135             Attribute attr = new Attribute(getName(), args[0]);
136             mbsc.setAttribute(name, attr);
137             return null;
138         }
139     }
140 
141     private static class InvokeHandler extends Handler {
InvokeHandler(String operationName, String[] signature, ConvertingMethod cm)142         InvokeHandler(String operationName, String[] signature,
143                       ConvertingMethod cm) {
144             super(operationName, cm);
145             this.signature = signature;
146         }
147 
invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)148         Object invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)
149                 throws Exception {
150             return mbsc.invoke(name, getName(), args, signature);
151         }
152 
153         private final String[] signature;
154     }
155 
invoke(MBeanServerConnection mbsc, ObjectName name, Method method, Object[] args)156     public Object invoke(MBeanServerConnection mbsc, ObjectName name,
157                          Method method, Object[] args)
158             throws Throwable {
159 
160         Handler handler = handlerMap.get(method);
161         ConvertingMethod cm = handler.getConvertingMethod();
162         MXBeanLookup lookup = MXBeanLookup.lookupFor(mbsc);
163         MXBeanLookup oldLookup = MXBeanLookup.getLookup();
164         try {
165             MXBeanLookup.setLookup(lookup);
166             Object[] openArgs = cm.toOpenParameters(lookup, args);
167             Object result = handler.invoke(mbsc, name, openArgs);
168             return cm.fromOpenReturnValue(lookup, result);
169         } finally {
170             MXBeanLookup.setLookup(oldLookup);
171         }
172     }
173 
174     private final Map<Method, Handler> handlerMap = newMap();
175 }
176