Frames | No Frames |
1: /* CompositeDataInvocationHandler.java - Pseudo-accessors for CompositeData. 2: Copyright (C) 2007 Free Software Foundation 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package javax.management.openmbean; 39: 40: import java.lang.reflect.InvocationHandler; 41: import java.lang.reflect.Method; 42: import java.lang.reflect.Proxy; 43: 44: /** 45: * <p> 46: * Provides an {@link java.lang.reflect.InvocationHandler} which 47: * implements a series of accessor methods (those beginning with 48: * {@code "get"} or {@code "is"}) using the content of a 49: * {@link CompositeData} object. An instance of {@link CompositeData} 50: * consists of a series of key-value mappings. This handler assumes 51: * these keys to be the names of attributes, and thus provides 52: * accessor methods by returning the associated value. 53: * </p> 54: * <p> 55: * As an example, consider the following interface: 56: * </p> 57: * <pre> 58: * public interface Person 59: * { 60: * public String getName(); 61: * public Date getBirthday(); 62: * } 63: * </pre> 64: * <p> 65: * This specifies two accessor methods for retrieving the attributes, 66: * {@code name} and {@code birthday}. An implementation of this interface 67: * can be provided by creating an instance of this class, using a 68: * {@link CompositeData} object with appropriate key-value mappings 69: * (e.g. "name" => "Fred", "birthday" => 30/06/1974), and then passing 70: * that to {@link java.lang.reflect.Proxy#newProxyInstance} along with 71: * the interface itself. The invocation handler implements the methods 72: * by calling {@link CompositeData#get(String)} with the appropriate key. 73: * </p> 74: * <p> 75: * The attribute name is derived by taking the remainder of the method 76: * name following {@code "get"}. If the first letter of this substring 77: * is uppercase, then two attempts are made to retrieve the attribute 78: * from the {@link CompositeData} instance: one using the original substring, 79: * and one with the first letter changed to its lower-case equivalent. 80: * If the first letter is lowercase, only the exact substring is used. 81: * </p> 82: * <p> 83: * An {@link Object#equals(Object)} implementation is provided. This returns 84: * true if the argument is a proxy with a {@link CompositeDataInvocationHandler} 85: * using an equivalent {@link CompositeData} instance. {@link Object#hashCode()} 86: * is also defined so as to match this implementation and give equivalent instances 87: * the same hashcode. 88: * </p> 89: * 90: * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 91: * @since 1.6 92: */ 93: public class CompositeDataInvocationHandler 94: implements InvocationHandler 95: { 96: 97: /** 98: * The {@link CompositeData} providing the key-value mappings. 99: */ 100: private CompositeData data; 101: 102: /** 103: * Constructs a new {@link CompositeDataInvocationHandler} 104: * with the specified {@link CompositeData} instance. 105: * 106: * @param data the {@link CompositeData} instance to use. 107: * @throws IllegalArgumentException if {@code data} is {@code null}. 108: */ 109: public CompositeDataInvocationHandler(CompositeData data) 110: { 111: if (data == null) 112: throw new IllegalArgumentException("The CompositeData instance " + 113: "must be non-null."); 114: this.data = data; 115: } 116: 117: /** 118: * Returns the {@link CompositeData} instance which provides 119: * the key-value mappings for this instance. This is never 120: * {@code null}. 121: * 122: * @return the {@link CompositeData} instance. 123: */ 124: public CompositeData getCompositeData() 125: { 126: return data; 127: } 128: 129: /** 130: * Called by the proxy class whenever a method is called. The 131: * handler only deals with accessor methods (beginning with 132: * {@code "get"} or {@code "is"}), {@code equals}, and 133: * {@code "hashCode"}. Accessor methods are implemented by 134: * returning the appropriate value from the {@link CompositeData} 135: * instance, while {@code equals} and {@code hashCode} allow 136: * two proxies with a {@link CompositeDataInvocationHandler} using 137: * the same {@link CompositeData} instance to be classified 138: * as equivalent. 139: * 140: * @param proxy the proxy on which the method was called. 141: * @param method the method which was called. 142: * @param args the arguments supplied to the method. 143: * @return the return value from the method. 144: * @throws Throwable if an exception is thrown in the process. 145: */ 146: public Object invoke(Object proxy, Method method, Object[] args) 147: throws Throwable 148: { 149: String mName = method.getName(); 150: if (mName.equals("equals")) 151: { 152: if (args[0] instanceof Proxy) 153: { 154: InvocationHandler h = Proxy.getInvocationHandler(args[0]); 155: if (h instanceof CompositeDataInvocationHandler) 156: return data.equals(((CompositeDataInvocationHandler) 157: h).getCompositeData()); 158: } 159: return false; 160: } 161: if (mName.equals("hashCode")) 162: { 163: return data.hashCode(); 164: } 165: String attrib = null; 166: if (mName.startsWith("get")) 167: attrib = mName.substring(3); 168: else if (mName.startsWith("is")) 169: attrib = mName.substring(2); 170: if (attrib == null) 171: throw new NoSuchMethodException(mName + " is not an accessor."); 172: if (!data.containsKey(attrib)) 173: { 174: if (Character.isLowerCase(attrib.charAt(0))) 175: throw new NoSuchMethodException("The attribute " + 176: attrib + " is not available " + 177: "in the given CompositeData " + 178: "object"); 179: attrib = Character.toLowerCase(attrib.charAt(0)) 180: + attrib.substring(1); 181: if (!data.containsKey(attrib)) 182: throw new NoSuchMethodException("The attribute " + 183: attrib + " is not available " + 184: "in the given CompositeData " + 185: "object"); 186: } 187: return data.get(attrib); 188: } 189: 190: }