Source code: com/chaoswg/xtc4y/proxy/InvocationStack.java
1 //$Header: /cvsroot/xtc4y/xtc4y/src/com/chaoswg/xtc4y/proxy/InvocationStack.java,v 1.1 2003/09/07 19:38:21 toggm Exp $
2 /******************************************************************************
3 * CHAOSWG.COM
4 * -------------------------------------------------------------------------- *
5 * URL: http://www.chaoswg.com/ *
6 * Author: Mike Toggweiler (2.dog@gmx.ch) *
7 * *
8 * Last Updated: $Date: 2003/09/07 19:38:21 $, by $Author: toggm $ *
9 * Version: $Revision: 1.1 $ *
10 * -------------------------------------------------------------------------- *
11 * COPYRIGHT: (c) 2003 by Mike Toggweiler *
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 *****************************************************************************/
18
19 package com.chaoswg.xtc4y.proxy;
20
21 //third company code imports
22 import java.util.*;
23 import java.lang.reflect.*;
24
25 //WIN imports
26
27 /**
28 * Invocation stack, used to trace calls on a class
29 * @author Mike Toggweiler
30 **/
31 public class InvocationStack implements InvocationHandler {
32 private Stack stack = new Stack();
33 private Object proxy;
34 private Object targetObject = null;
35 private Class targetClass;
36 private HashMap returnValues = new HashMap();
37
38 /**
39 * Creates a new invocation stack and a proxy of a class
40 * if methods are invoked on this proxy, they are traced and
41 * default values are returned.
42 **/
43 public InvocationStack(Class target) {
44 try {
45 targetClass = target;
46 Class proxyClass =
47 Proxy.getProxyClass(target.getClassLoader(),
48 new Class[] {target});
49 proxy = proxyClass.
50 getConstructor(new Class[] {InvocationHandler.class}).
51 newInstance(new Object[] {this});
52 }
53 catch (Exception e) {
54 throw new RuntimeException(e);
55 }
56 }
57
58 /**
59 * Creates a new invocationstack and a proxy of the given object.
60 * if methods are invoked in the proxy, they are traced and the
61 * invocations are redirected to the target object
62 **/
63 public InvocationStack(Object target) {
64 this(target.getClass());
65 targetObject = target;
66 }
67
68 /**
69 * @return the proxy object
70 **/
71 public Object getProxyObject() {
72 return proxy;
73 }
74
75 /**
76 * @return the last MethodContainer element in the stack or null
77 * if empty, remove it atfter returning
78 **/
79 public MethodContainer popStack() {
80 try {
81 return (MethodContainer)stack.pop();
82 }
83 catch (EmptyStackException ese) {
84 return null;
85 }
86 }
87
88 /**
89 * @return the last MethodContainer element in the stack or null
90 * if empty, without removing it
91 **/
92 public MethodContainer peekStack() {
93 try {
94 return (MethodContainer)stack.peek();
95 }
96 catch (EmptyStackException ese) {
97 return null;
98 }
99 }
100
101 /**
102 * Empty stack
103 **/
104 public void emptyStack() {
105 stack.removeAllElements();
106 }
107
108 /**
109 * @return the first method matching without checking paramter types
110 * this should only be used if there is just one method with this name
111 **/
112 public Method getMethod(String name) {
113 Method[] methods = targetClass.getMethods();
114 for (int i=0; i<methods.length; ++i) {
115 if (methods[i].getName().equals(name)) {
116 return methods[i];
117 }
118 }
119 throw new RuntimeException(new NoSuchMethodException(name));
120 }
121
122 /**
123 * @return the method matching the name and parameter types
124 **/
125 public Method getMethod(String name, Class[] params) {
126 try {
127 return targetClass.getMethod(name, params);
128 }
129 catch (NoSuchMethodException nsme) {
130 throw new RuntimeException(nsme);
131 }
132 }
133
134 /**
135 * set a return value for a specific method
136 * @param method method to define the return value
137 * @param Object return value
138 **/
139 public void setReturnValue(Method method, Object value) {
140 returnValues.put(method, value);
141 }
142
143 /**
144 * Remove a previously defined return value for a method
145 * @param method the method for which the return value should be
146 * removed
147 **/
148 public void removeReturnValue(Method method) {
149 returnValues.remove(method);
150 }
151
152 /**
153 * Implementation of a InvocationHandler
154 **/
155 public Object invoke(Object obj, Method method, Object[] args)
156 throws Throwable {
157
158 //store on stack
159 stack.push(new MethodContainer(method, args));
160
161 //check first if a special return value was defined before
162 if (returnValues.containsKey(method)) {
163 return returnValues.get(method);
164 }
165
166 //if target object is specified, redirect invocation
167 if (targetObject != null) {
168 return method.invoke(targetObject, args);
169 }
170
171 //try to invoke the invoke an implemented method on an abstract class
172 int mod = method.getModifiers();
173 if (!Modifier.isAbstract(mod)) {
174 return method.invoke(obj, args);
175 }
176
177 Class retType = method.getReturnType();
178 if (!retType.isPrimitive()) {
179 return retType.newInstance();
180 }
181 else {
182 if (retType.isAssignableFrom(Integer.TYPE)) {
183 return new Integer(0);
184 }
185 else if (retType.isAssignableFrom(Long.TYPE)) {
186 return new Long(0);
187 }
188 else if (retType.isAssignableFrom(Short.TYPE)) {
189 return new Short((short)0);
190 }
191 else if (retType.isAssignableFrom(Double.TYPE)) {
192 return new Double(0);
193 }
194 else if (retType.isAssignableFrom(Float.TYPE)) {
195 return new Float(0);
196 }
197 else if (retType.isAssignableFrom(Boolean.TYPE)) {
198 return new Boolean(false);
199 }
200 else if (retType.isAssignableFrom(Character.TYPE)) {
201 return new Character(' ');
202 }
203 else if (retType.isAssignableFrom(Byte.TYPE)) {
204 return new Byte((byte)0);
205 }
206 else if (retType.isAssignableFrom(Void.TYPE)) {
207 return null;
208 }
209 }
210 return null;
211 }
212 }