1 /**
2 *
3 * Copyright 2003-2004 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.geronimo.gbean;
19
20 import java.beans.Introspector;
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.List;
27 import java.util.ArrayList;
28 import java.util.Iterator;
29
30 import net.sf.cglib.reflect.FastClass;
31 import net.sf.cglib.reflect.FastMethod;
32
33
34 /**
35 * Wraps an <code>Object</code> in a <code>DynamicGBean</code> facade.
36 *
37 * @version $Rev: 355877 $ $Date: 2005-12-10 18:48:27 -0800 (Sat, 10 Dec 2005) $
38 */
39 public class DynamicGBeanDelegate implements DynamicGBean {
40 protected final Map getters = new HashMap();
41 protected final Map setters = new HashMap();
42 protected final Map operations = new HashMap();
43 private Class targetClass;
44
45 public void addAll(Object target) {
46 this.targetClass = target.getClass();
47 Method[] methods = targetClass.getMethods();
48 for (int i = 0; i < methods.length; i++) {
49 Method method = methods[i];
50 if (isGetter(method)) {
51 addGetter(target, method);
52 } else if (isSetter(method)) {
53 addSetter(target, method);
54 } else {
55 addOperation(target, method);
56 }
57 }
58 }
59
60 public void addGetter(Object target, Method method) {
61 String name = method.getName();
62 if (name.startsWith("get")) {
63 addGetter(name.substring(3), target, method);
64 } else if (name.startsWith("is")) {
65 addGetter(name.substring(2), target, method);
66 } else {
67 throw new IllegalArgumentException("Method name must start with 'get' or 'is' " + method);
68 }
69 }
70
71 public void addGetter(String name, Object target, Method method) {
72 if (!(method.getParameterTypes().length == 0 && method.getReturnType() != Void.TYPE)) {
73 throw new IllegalArgumentException("Method must take no parameters and return a value " + method);
74 }
75 getters.put(name, new Operation(target, method));
76
77
78 getters.put(Introspector.decapitalize(name), new Operation(target, method));
79 }
80
81 public void addSetter(Object target, Method method) {
82 if (!method.getName().startsWith("set")) {
83 throw new IllegalArgumentException("Method name must start with 'set' " + method);
84 }
85 addSetter(method.getName().substring(3), target, method);
86 }
87
88 public void addSetter(String name, Object target, Method method) {
89 if (!(method.getParameterTypes().length == 1 && method.getReturnType() == Void.TYPE)) {
90 throw new IllegalArgumentException("Method must take one parameter and not return anything " + method);
91 }
92 setters.put(name, new Operation(target, method));
93
94
95 setters.put(Introspector.decapitalize(name), new Operation(target, method));
96 }
97
98 public void addOperation(Object target, Method method) {
99 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 }