1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package de.bea.domingo.service;
24
25 import java.lang.reflect.InvocationHandler;
26 import java.lang.reflect.Method;
27 import java.lang.reflect.Proxy;
28 import java.util.ArrayList;
29 import java.util.Calendar;
30 import java.util.List;
31
32 import de.bea.domingo.DDateRange;
33 import de.bea.domingo.DNotesFactory;
34
35 /***
36 * Invocation handler for all dynamic proxies of interfaces of the
37 * domingo API.
38 *
39 * <p>This class is responsible to separate internal objects from external
40 * proxies, where especially arguments and return values must be extracted
41 * and wrapped thru each method invocation</p>.
42 *
43 * @author <a href=mailto:kriede@users.sourceforge.net>Kurt Riede</a>
44 */
45 public final class NotesInvocationHandler implements InvocationHandler {
46
47 /*** Reference to Object to invoke on. */
48 private final Object object;
49
50 /***
51 * Constructor.
52 * @param theObject the wrapped object
53 */
54 public NotesInvocationHandler(final Object theObject) {
55 super();
56 object = theObject;
57 }
58
59 /***
60 * Getter method for object attribute.
61 *
62 * @return associated object.
63 */
64 Object getObject() {
65 return object;
66 }
67
68 /***
69 * Processes a method invocation on a proxy instance and returns the result.
70 * <p>All arguments that are proxies to a NotesInvocationHandler are
71 * extracted from the proxy to the original objects. If the resulting object
72 * is a Notes object, a new proxy will be created.</p>
73 *
74 * <p><b>Further Details from
75 * {@link java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method,
76 * java.lang.Object[])}:</b></p>
77 * <p>{@inheritDoc}</p>
78 *
79 * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
80 * java.lang.reflect.Method, java.lang.Object[])
81 */
82 public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
83 final NotesServiceFactory factory = (NotesServiceFactory) DNotesFactory.getInstance();
84 final Object result;
85 final Object[] extractedArgs = extractArguments(args);
86 try {
87 result = factory.invoke(object, method, extractedArgs);
88 } catch (Throwable t) {
89 NotesJavaWriter.getInstance().logInvocation(null, object, method, extractedArgs, t);
90 throw t;
91 }
92 NotesJavaWriter.getInstance().logInvocation(result, object, method, extractedArgs, null);
93 return packObject(result);
94 }
95
96 /***
97 * Extracts all arguments that are dynamic proxies.
98 *
99 * @param args array of objects
100 * @return array of extracted objects
101 */
102 private Object[] extractArguments(final Object[] args) {
103 Object[] extractedArgs;
104 if (args == null) {
105 extractedArgs = null;
106 } else {
107 extractedArgs = new Object[args.length];
108 for (int i = 0; i < args.length; i++) {
109 if (args[i] == null) {
110 extractedArgs[i] = null;
111 } else if (Proxy.isProxyClass(args[i].getClass())) {
112 extractedArgs[i] = extractObject(args[i]);
113 } else {
114 extractedArgs[i] = args[i];
115 }
116 }
117 }
118 return extractedArgs;
119 }
120
121 /***
122 * Extracts an object if it is a dynamic proxy.
123 *
124 * @param obj an object
125 * @return extracted object
126 */
127 private Object extractObject(final Object obj) {
128 final InvocationHandler invocationHandler = Proxy.getInvocationHandler(obj);
129 if (invocationHandler instanceof NotesInvocationHandler) {
130 return ((NotesInvocationHandler) invocationHandler).getObject();
131 } else {
132 return obj;
133 }
134 }
135
136 /***
137 * Packs an object into a dynamic proxy if it is a Domingo object.
138 *
139 * @param obj an object
140 * @return packed object
141 */
142 private Object packObject(final Object obj) {
143 if (obj == null) {
144 return obj;
145 } else if (obj instanceof Calendar) {
146 return obj;
147 } else if (obj instanceof DDateRange) {
148 return obj;
149 } else if (obj.getClass().getPackage().getName().startsWith("de.bea.domingo")) {
150 return wrapObject(obj);
151 } else if (obj instanceof List) {
152 final List list = new ArrayList((List) obj);
153 for (int i = 0; i < list.size(); i++) {
154 if (list.get(i) != null) {
155 if (list.get(i).getClass().getPackage().getName().startsWith("de.bea.domingo")) {
156 set(list, i);
157 }
158 }
159 }
160 }
161 return obj;
162 }
163
164 private void set(final List list, final int i) {
165 Object obj = list.get(i);
166 Object pack = packObject(obj);
167 if (pack != obj) {
168 list.set(i, pack);
169 }
170 }
171
172 /***
173 * Wraps an object into a dynamic proxy.
174 *
175 * @param obj the object to wrap
176 * @return the wrapped object
177 */
178 private Object wrapObject(final Object obj) {
179 return getNotesProxy(obj.getClass().getInterfaces(), obj);
180 }
181
182 /***
183 * Creates a Proxy for an Interface to an Object.
184 *
185 * @param theInterfaces array of interface of the proxy
186 * @param theObject th object to be wrapped
187 * @return proxy object
188 */
189 public static Object getNotesProxy(final Class[] theInterfaces, final Object theObject) {
190 return Proxy.newProxyInstance(
191 theObject.getClass().getClassLoader(),
192 theInterfaces,
193 new NotesInvocationHandler(theObject));
194 }
195 }