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: */package org.apache.geronimo.gbean;
017:
018: import java.beans.Introspector;
019: import java.lang.reflect.InvocationTargetException;
020: import java.lang.reflect.Method;
021: import java.util.HashMap;
022: import java.util.Map;
023: import java.util.Set;
024: import java.util.List;
025: import java.util.ArrayList;
026: import java.util.Iterator;
027:
028: import net.sf.cglib.reflect.FastClass;
029: import net.sf.cglib.reflect.FastMethod;
030:
031: /**
032: * Wraps an <code>Object</code> in a <code>DynamicGBean</code> facade.
033: *
034: * @version $Rev: 476049 $ $Date: 2006-11-16 20:35:17 -0800 (Thu, 16 Nov 2006) $
035: */
036: public class DynamicGBeanDelegate implements DynamicGBean {
037: protected final Map getters = new HashMap();
038: protected final Map setters = new HashMap();
039: protected final Map operations = new HashMap();
040: private Class targetClass;
041:
042: public void addAll(Object target) {
043: this .targetClass = target.getClass();
044: Method[] methods = targetClass.getMethods();
045: for (int i = 0; i < methods.length; i++) {
046: Method method = methods[i];
047: if (isGetter(method)) {
048: addGetter(target, method);
049: } else if (isSetter(method)) {
050: addSetter(target, method);
051: } else {
052: addOperation(target, method);
053: }
054: }
055: }
056:
057: public void addGetter(Object target, Method method) {
058: String name = method.getName();
059: if (name.startsWith("get")) {
060: addGetter(name.substring(3), target, method);
061: } else if (name.startsWith("is")) {
062: addGetter(name.substring(2), target, method);
063: } else {
064: throw new IllegalArgumentException(
065: "Method name must start with 'get' or 'is' "
066: + method);
067: }
068: }
069:
070: public void addGetter(String name, Object target, Method method) {
071: if (!(method.getParameterTypes().length == 0 && method
072: .getReturnType() != Void.TYPE)) {
073: throw new IllegalArgumentException(
074: "Method must take no parameters and return a value "
075: + method);
076: }
077: getters.put(name, new Operation(target, method));
078: // we want to be user-friendly so we put the attribute name in
079: // the Map in both lower-case and upper-case
080: getters.put(Introspector.decapitalize(name), new Operation(
081: target, method));
082: }
083:
084: public void addSetter(Object target, Method method) {
085: if (!method.getName().startsWith("set")) {
086: throw new IllegalArgumentException(
087: "Method name must start with 'set' " + method);
088: }
089: addSetter(method.getName().substring(3), target, method);
090: }
091:
092: public void addSetter(String name, Object target, Method method) {
093: if (!(method.getParameterTypes().length == 1 && method
094: .getReturnType() == Void.TYPE)) {
095: throw new IllegalArgumentException(
096: "Method must take one parameter and not return anything "
097: + method);
098: }
099: setters.put(name, new Operation(target, method));
100: // we want to be user-friendly so we put the attribute name in
101: // the Map in both lower-case and upper-case
102: setters.put(Introspector.decapitalize(name), new Operation(
103: target, method));
104: }
105:
106: public void addOperation(Object target, Method method) {
107: Class[] parameters = method.getParameterTypes();
108: String[] types = new String[parameters.length];
109: for (int i = 0; i < parameters.length; i++) {
110: types[i] = parameters[i].getName();
111: }
112: GOperationSignature key = new GOperationSignature(method
113: .getName(), types);
114: operations.put(key, new Operation(target, method));
115: }
116:
117: private boolean isGetter(Method method) {
118: String name = method.getName();
119: return (name.startsWith("get") || name.startsWith("is"))
120: && method.getParameterTypes().length == 0
121: && method.getReturnType() != Void.TYPE;
122: }
123:
124: private boolean isSetter(Method method) {
125: return method.getName().startsWith("set")
126: && method.getParameterTypes().length == 1
127: && method.getReturnType() == Void.TYPE;
128: }
129:
130: public Object getAttribute(String name) throws Exception {
131: Operation operation = (Operation) getters.get(name);
132: if (operation == null) {
133: throw new IllegalArgumentException(targetClass.getName()
134: + ": no getter for " + name);
135: }
136: return operation.invoke(null);
137: }
138:
139: public void setAttribute(String name, Object value)
140: throws Exception {
141: Operation operation = (Operation) setters.get(name);
142: if (operation == null) {
143: throw new IllegalArgumentException(targetClass.getName()
144: + ": no setter for " + name);
145: }
146: operation.invoke(new Object[] { value });
147: }
148:
149: public Object invoke(String name, Object[] arguments, String[] types)
150: throws Exception {
151: GOperationSignature signature = new GOperationSignature(name,
152: types);
153: Operation operation = (Operation) operations.get(signature);
154: if (operation == null) {
155: throw new IllegalArgumentException(targetClass.getName()
156: + ": no operation " + signature);
157: }
158: return operation.invoke(arguments);
159: }
160:
161: /**
162: * Gets all properties (with both a getter and setter), in the form of
163: * propertyName
164: */
165: public String[] getProperties() {
166: Set one = getters.keySet();
167: Set two = setters.keySet();
168: List out = new ArrayList();
169: for (Iterator it = one.iterator(); it.hasNext();) {
170: String name = (String) it.next();
171: if (Character.isLowerCase(name.charAt(0))
172: && two.contains(name)) {
173: out.add(name);
174: }
175: }
176: return (String[]) out.toArray(new String[out.size()]);
177: }
178:
179: public Class getPropertyType(String name) {
180: Operation oper = (Operation) getters.get(name);
181: return oper.method.getReturnType();
182: }
183:
184: protected static class Operation {
185: private final Object target;
186: private final FastMethod method;
187:
188: public Operation(Object target, Method method) {
189: assert target != null;
190: assert method != null;
191: this .target = target;
192: this .method = FastClass.create(target.getClass())
193: .getMethod(method);
194: }
195:
196: public Object invoke(Object[] arguments) throws Exception {
197: try {
198: return method.invoke(target, arguments);
199: } catch (InvocationTargetException e) {
200: Throwable targetException = e.getTargetException();
201: if (targetException instanceof Exception) {
202: throw (Exception) targetException;
203: } else if (targetException instanceof Error) {
204: throw (Error) targetException;
205: }
206: throw e;
207: }
208: }
209: }
210: }
|