001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. 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: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $
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 }