1/* 2 * Copyright (c) 2005, 2013, 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 26package com.sun.jmx.mbeanserver; 27import java.io.InvalidObjectException; 28import java.lang.reflect.InvocationTargetException; 29import java.lang.reflect.Method; 30import java.lang.reflect.Type; 31 32import javax.management.Descriptor; 33import javax.management.MBeanException; 34import javax.management.openmbean.OpenDataException; 35import javax.management.openmbean.OpenType; 36import sun.reflect.misc.MethodUtil; 37 38final class ConvertingMethod { 39 static ConvertingMethod from(Method m) { 40 try { 41 return new ConvertingMethod(m); 42 } catch (OpenDataException ode) { 43 final String msg = "Method " + m.getDeclaringClass().getName() + 44 "." + m.getName() + " has parameter or return type that " + 45 "cannot be translated into an open type"; 46 throw new IllegalArgumentException(msg, ode); 47 } 48 } 49 50 Method getMethod() { 51 return method; 52 } 53 54 Descriptor getDescriptor() { 55 return Introspector.descriptorForElement(method); 56 } 57 58 Type getGenericReturnType() { 59 return method.getGenericReturnType(); 60 } 61 62 Type[] getGenericParameterTypes() { 63 return method.getGenericParameterTypes(); 64 } 65 66 String getName() { 67 return method.getName(); 68 } 69 70 OpenType<?> getOpenReturnType() { 71 return returnMapping.getOpenType(); 72 } 73 74 OpenType<?>[] getOpenParameterTypes() { 75 final OpenType<?>[] types = new OpenType<?>[paramMappings.length]; 76 for (int i = 0; i < paramMappings.length; i++) 77 types[i] = paramMappings[i].getOpenType(); 78 return types; 79 } 80 81 /* Check that this method will be callable when we are going from 82 * open types to Java types, for example when we are going from 83 * an MXBean wrapper to the underlying resource. 84 * The parameters will be converted to 85 * Java types, so they must be "reconstructible". The return 86 * value will be converted to an Open Type, so if it is convertible 87 * at all there is no further check needed. 88 */ 89 void checkCallFromOpen() { 90 try { 91 for (MXBeanMapping paramConverter : paramMappings) 92 paramConverter.checkReconstructible(); 93 } catch (InvalidObjectException e) { 94 throw new IllegalArgumentException(e); 95 } 96 } 97 98 /* Check that this method will be callable when we are going from 99 * Java types to open types, for example when we are going from 100 * an MXBean proxy to the open types that it will be mapped to. 101 * The return type will be converted back to a Java type, so it 102 * must be "reconstructible". The parameters will be converted to 103 * open types, so if it is convertible at all there is no further 104 * check needed. 105 */ 106 void checkCallToOpen() { 107 try { 108 returnMapping.checkReconstructible(); 109 } catch (InvalidObjectException e) { 110 throw new IllegalArgumentException(e); 111 } 112 } 113 114 String[] getOpenSignature() { 115 if (paramMappings.length == 0) 116 return noStrings; 117 118 String[] sig = new String[paramMappings.length]; 119 for (int i = 0; i < paramMappings.length; i++) 120 sig[i] = paramMappings[i].getOpenClass().getName(); 121 return sig; 122 } 123 124 final Object toOpenReturnValue(MXBeanLookup lookup, Object ret) 125 throws OpenDataException { 126 return returnMapping.toOpenValue(ret); 127 } 128 129 final Object fromOpenReturnValue(MXBeanLookup lookup, Object ret) 130 throws InvalidObjectException { 131 return returnMapping.fromOpenValue(ret); 132 } 133 134 final Object[] toOpenParameters(MXBeanLookup lookup, Object[] params) 135 throws OpenDataException { 136 if (paramConversionIsIdentity || params == null) 137 return params; 138 final Object[] oparams = new Object[params.length]; 139 for (int i = 0; i < params.length; i++) 140 oparams[i] = paramMappings[i].toOpenValue(params[i]); 141 return oparams; 142 } 143 144 final Object[] fromOpenParameters(Object[] params) 145 throws InvalidObjectException { 146 if (paramConversionIsIdentity || params == null) 147 return params; 148 final Object[] jparams = new Object[params.length]; 149 for (int i = 0; i < params.length; i++) 150 jparams[i] = paramMappings[i].fromOpenValue(params[i]); 151 return jparams; 152 } 153 154 final Object toOpenParameter(MXBeanLookup lookup, 155 Object param, 156 int paramNo) 157 throws OpenDataException { 158 return paramMappings[paramNo].toOpenValue(param); 159 } 160 161 final Object fromOpenParameter(MXBeanLookup lookup, 162 Object param, 163 int paramNo) 164 throws InvalidObjectException { 165 return paramMappings[paramNo].fromOpenValue(param); 166 } 167 168 Object invokeWithOpenReturn(MXBeanLookup lookup, 169 Object obj, Object[] params) 170 throws MBeanException, IllegalAccessException, 171 InvocationTargetException { 172 MXBeanLookup old = MXBeanLookup.getLookup(); 173 try { 174 MXBeanLookup.setLookup(lookup); 175 return invokeWithOpenReturn(obj, params); 176 } finally { 177 MXBeanLookup.setLookup(old); 178 } 179 } 180 181 private Object invokeWithOpenReturn(Object obj, Object[] params) 182 throws MBeanException, IllegalAccessException, 183 InvocationTargetException { 184 final Object[] javaParams; 185 try { 186 javaParams = fromOpenParameters(params); 187 } catch (InvalidObjectException e) { 188 // probably can't happen 189 final String msg = methodName() + ": cannot convert parameters " + 190 "from open values: " + e; 191 throw new MBeanException(e, msg); 192 } 193 final Object javaReturn = MethodUtil.invoke(method, obj, javaParams); 194 try { 195 return returnMapping.toOpenValue(javaReturn); 196 } catch (OpenDataException e) { 197 // probably can't happen 198 final String msg = methodName() + ": cannot convert return " + 199 "value to open value: " + e; 200 throw new MBeanException(e, msg); 201 } 202 } 203 204 private String methodName() { 205 return method.getDeclaringClass() + "." + method.getName(); 206 } 207 208 private ConvertingMethod(Method m) throws OpenDataException { 209 this.method = m; 210 MXBeanMappingFactory mappingFactory = MXBeanMappingFactory.DEFAULT; 211 returnMapping = 212 mappingFactory.mappingForType(m.getGenericReturnType(), mappingFactory); 213 Type[] params = m.getGenericParameterTypes(); 214 paramMappings = new MXBeanMapping[params.length]; 215 boolean identity = true; 216 for (int i = 0; i < params.length; i++) { 217 paramMappings[i] = mappingFactory.mappingForType(params[i], mappingFactory); 218 identity &= DefaultMXBeanMappingFactory.isIdentity(paramMappings[i]); 219 } 220 paramConversionIsIdentity = identity; 221 } 222 223 private static final String[] noStrings = new String[0]; 224 225 private final Method method; 226 private final MXBeanMapping returnMapping; 227 private final MXBeanMapping[] paramMappings; 228 private final boolean paramConversionIsIdentity; 229} 230