View Javadoc

1   /*
2    * This file is part of Domingo
3    * an Open Source Java-API to Lotus Notes/Domino
4    * hosted at http://domingo.sourceforge.net
5    *
6    * Copyright (c) 2003-2007 Beck et al. projects GmbH Munich, Germany (http://www.bea.de)
7    *
8    * This library is free software; you can redistribute it and/or
9    * modify it under the terms of the GNU Lesser General Public
10   * License as published by the Free Software Foundation; either
11   * version 2.1 of the License, or (at your option) any later version.
12   *
13   * This library is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   * Lesser General Public License for more details.
17   *
18   * You should have received a copy of the GNU Lesser General Public
19   * License along with this library; if not, write to the Free Software
20   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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 }