001 /** 002 * 003 * Copyright 2003-2004 The Apache Software Foundation 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.geronimo.gbean; 019 020 import java.beans.Introspector; 021 import java.lang.reflect.InvocationTargetException; 022 import java.lang.reflect.Method; 023 import java.util.HashMap; 024 import java.util.Map; 025 import java.util.Set; 026 import java.util.List; 027 import java.util.ArrayList; 028 import java.util.Iterator; 029 030 import net.sf.cglib.reflect.FastClass; 031 import net.sf.cglib.reflect.FastMethod; 032 033 034 /** 035 * Wraps an <code>Object</code> in a <code>DynamicGBean</code> facade. 036 * 037 * @version $Rev: 355877 $ $Date: 2005-12-10 18:48:27 -0800 (Sat, 10 Dec 2005) $ 038 */ 039 public class DynamicGBeanDelegate implements DynamicGBean { 040 protected final Map getters = new HashMap(); 041 protected final Map setters = new HashMap(); 042 protected final Map operations = new HashMap(); 043 private Class targetClass; 044 045 public void addAll(Object target) { 046 this.targetClass = target.getClass(); 047 Method[] methods = targetClass.getMethods(); 048 for (int i = 0; i < methods.length; i++) { 049 Method method = methods[i]; 050 if (isGetter(method)) { 051 addGetter(target, method); 052 } else if (isSetter(method)) { 053 addSetter(target, method); 054 } else { 055 addOperation(target, method); 056 } 057 } 058 } 059 060 public void addGetter(Object target, Method method) { 061 String name = method.getName(); 062 if (name.startsWith("get")) { 063 addGetter(name.substring(3), target, method); 064 } else if (name.startsWith("is")) { 065 addGetter(name.substring(2), target, method); 066 } else { 067 throw new IllegalArgumentException("Method name must start with 'get' or 'is' " + method); 068 } 069 } 070 071 public void addGetter(String name, Object target, Method method) { 072 if (!(method.getParameterTypes().length == 0 && method.getReturnType() != Void.TYPE)) { 073 throw new IllegalArgumentException("Method must take no parameters and return a value " + method); 074 } 075 getters.put(name, new Operation(target, method)); 076 // we want to be user-friendly so we put the attribute name in 077 // the Map in both lower-case and upper-case 078 getters.put(Introspector.decapitalize(name), new Operation(target, method)); 079 } 080 081 public void addSetter(Object target, Method method) { 082 if (!method.getName().startsWith("set")) { 083 throw new IllegalArgumentException("Method name must start with 'set' " + method); 084 } 085 addSetter(method.getName().substring(3), target, method); 086 } 087 088 public void addSetter(String name, Object target, Method method) { 089 if (!(method.getParameterTypes().length == 1 && method.getReturnType() == Void.TYPE)) { 090 throw new IllegalArgumentException("Method must take one parameter and not return anything " + method); 091 } 092 setters.put(name, new Operation(target, method)); 093 // we want to be user-friendly so we put the attribute name in 094 // the Map in both lower-case and upper-case 095 setters.put(Introspector.decapitalize(name), new Operation(target, method)); 096 } 097 098 public void addOperation(Object target, Method method) { 099 Class[] parameters = method.getParameterTypes(); 100 String[] types = new String[parameters.length]; 101 for (int i = 0; i < parameters.length; i++) { 102 types[i] = parameters[i].getName(); 103 } 104 GOperationSignature key = new GOperationSignature(method.getName(), types); 105 operations.put(key, new Operation(target, method)); 106 } 107 108 private boolean isGetter(Method method) { 109 String name = method.getName(); 110 return (name.startsWith("get") || name.startsWith("is")) && 111 method.getParameterTypes().length == 0 112 && method.getReturnType() != Void.TYPE; 113 } 114 115 private boolean isSetter(Method method) { 116 return method.getName().startsWith("set") && 117 method.getParameterTypes().length == 1 && 118 method.getReturnType() == Void.TYPE; 119 } 120 121 public Object getAttribute(String name) throws Exception { 122 Operation operation = (Operation) getters.get(name); 123 if (operation == null) { 124 throw new IllegalArgumentException(targetClass.getName() + ": no getter for " + name); 125 } 126 return operation.invoke(null); 127 } 128 129 public void setAttribute(String name, Object value) throws Exception { 130 Operation operation = (Operation) setters.get(name); 131 if (operation == null) { 132 throw new IllegalArgumentException(targetClass.getName() + ": no setter for " + name); 133 } 134 operation.invoke(new Object[]{value}); 135 } 136 137 public Object invoke(String name, Object[] arguments, String[] types) throws Exception { 138 GOperationSignature signature = new GOperationSignature(name, types); 139 Operation operation = (Operation) operations.get(signature); 140 if (operation == null) { 141 throw new IllegalArgumentException(targetClass.getName() + ": no operation " + signature); 142 } 143 return operation.invoke(arguments); 144 } 145 146 /** 147 * Gets all properties (with both a getter and setter), in the form of 148 * propertyName 149 */ 150 public String[] getProperties() { 151 Set one = getters.keySet(); 152 Set two = setters.keySet(); 153 List out = new ArrayList(); 154 for (Iterator it = one.iterator(); it.hasNext();) { 155 String name = (String) it.next(); 156 if(Character.isLowerCase(name.charAt(0)) && two.contains(name)) { 157 out.add(name); 158 } 159 } 160 return (String[]) out.toArray(new String[out.size()]); 161 } 162 163 public Class getPropertyType(String name) { 164 Operation oper = (Operation) getters.get(name); 165 return oper.method.getReturnType(); 166 } 167 168 protected static class Operation { 169 private final Object target; 170 private final FastMethod method; 171 172 public Operation(Object target, Method method) { 173 assert target != null; 174 assert method != null; 175 this.target = target; 176 this.method = FastClass.create(target.getClass()).getMethod(method); 177 } 178 179 public Object invoke(Object[] arguments) throws Exception { 180 try { 181 return method.invoke(target, arguments); 182 } catch (InvocationTargetException e) { 183 Throwable targetException = e.getTargetException(); 184 if (targetException instanceof Exception) { 185 throw (Exception) targetException; 186 } else if (targetException instanceof Error) { 187 throw (Error) targetException; 188 } 189 throw e; 190 } 191 } 192 } 193 }