EMMA Coverage Report (generated Mon Mar 20 21:34:30 PST 2006)
[all classes][com.moesol.bindings]

COVERAGE SUMMARY FOR SOURCE FILE [DispatchJavaMethod.java]

nameclass, %method, %block, %line, %
DispatchJavaMethod.java100% (1/1)100% (15/15)83%  (195/234)88%  (44/50)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DispatchJavaMethod100% (1/1)100% (15/15)83%  (195/234)88%  (44/50)
findDispClassForIID (Object, GUID): Class 100% (1/1)60%  (25/42)80%  (4/5)
findDispClassFromInterface (Class, Class []): boolean 100% (1/1)67%  (26/39)83%  (5/6)
isSameInterface (Class, Field, GUID): boolean 100% (1/1)75%  (18/24)67%  (4/6)
fillInMethod (Class): void 100% (1/1)92%  (12/13)75%  (3/4)
findDispClassForIID (Class, GUID, Class []): boolean 100% (1/1)95%  (36/38)89%  (8/9)
DispatchJavaMethod (int, short, String, String): void 100% (1/1)100% (18/18)100% (7/7)
getDispId (): int 100% (1/1)100% (3/3)100% (1/1)
getInvKind (): short 100% (1/1)100% (3/3)100% (1/1)
getJavaMethod (): Method 100% (1/1)100% (3/3)100% (1/1)
getMethod (Class, String, String): Method 100% (1/1)100% (5/5)100% (1/1)
getMethodName (): String 100% (1/1)100% (3/3)100% (1/1)
getMethodSig (): String 100% (1/1)100% (3/3)100% (1/1)
invoke (Object, Object []): Object 100% (1/1)100% (6/6)100% (1/1)
isMatch (int, short): boolean 100% (1/1)100% (12/12)100% (1/1)
isSameInterface (Class, GUID): boolean 100% (1/1)100% (22/22)100% (5/5)

1/*
2 * $Id: DispatchJavaMethod.java,v 1.2 2005/12/01 06:10:00 hastings Exp $
3 * 
4 * Copyright (c) 2004, Moebius Solutions, Inc.
5 * All rights reserved.
6 * 
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 
11 *     Redistributions of source code must retain the above copyright
12 *     notice, this list of conditions and the following disclaimer.
13 * 
14 *     Redistributions in binary form must reproduce the above
15 *     copyright notice, this list of conditions and the following
16 *     disclaimer in the documentation and/or other materials provided
17 *     with the distribution.
18 * 
19 *     Neither the name of Moebius Solutions, Inc. nor the names of
20 *     its contributors may be used to endorse or promote products
21 *     derived from this software without specific prior written
22 *     permission.
23 * 
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
35 * OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37package com.moesol.bindings;
38 
39import java.lang.reflect.Field;
40import java.lang.reflect.InvocationTargetException;
41import java.lang.reflect.Method;
42 
43import com.moesol.bindings.platform_sdk.component_services.COMException;
44import com.moesol.bindings.platform_sdk.component_services.GUID;
45import com.moesol.bindings.platform_sdk.component_services.HRESULT;
46 
47/**
48 * Internal helper. Record the dispatch id, invocation kind, reflection method,
49 * method name, and method signature. This class is used by the native
50 * GenericIDispatch class to call the correct Java method when IDispatch::Invoke
51 * is called. It is also used by the ComInterfaceThunk to call the correct Java
52 * method when the vtable entry is thunked.
53 */
54public class DispatchJavaMethod {
55        /**
56         * Construct a Dispatch ID to Java Method mapping.
57         * 
58         * @param disp_id
59         *            dispatch id
60         * @param invkind
61         *            invocation kind (DISPATCH_METHOD, DISPATCH_PROPERTYGET,
62         *            DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF).
63         * @param name
64         *            Java method name
65         * @param sig
66         *            JNI method signature
67         */
68        public DispatchJavaMethod(int disp_id, short invkind, String name, String sig) {
69                m_disp_id = disp_id;
70                m_invkind = invkind;
71                m_java_method = null;
72                m_method_name = name;
73                m_method_sig = sig;
74        }
75 
76        /**
77         * Find the Disp implementation class for an IID. This is a relatively slow
78         * search, so users of this method will probably want to cache the results.
79         * 
80         * @param object
81         *            A Java object we think implements an interface with an IID of
82         *            <code>iid</code>.
83         * @param iid
84         *            The GUID we are trying to find.
85         * @return The Class found. If we are looking for IFoo.IID then we will
86         *         return IFoo.Disp
87         * @throws COMException
88         *             if we cannot find the class.
89         */
90        public static Class findDispClassForIID(Object object, GUID iid) {
91                Class[] out_class = { null };
92                for (Class c = object.getClass(); c != null; c = c.getSuperclass()) {  
93                        if (findDispClassForIID(c, iid, out_class)) {
94                                return out_class[0];
95                        }
96                }
97                
98                throw new COMException("Failed to find interface for IID, object="
99                                + object + " iid=" + iid, HRESULT.E_NOINTERFACE);
100        }
101 
102        /**
103         * @param object_class
104         * @param iid
105         * @return null if not found
106         */
107        private static boolean findDispClassForIID(Class object_class, GUID iid, Class[] out_class) {
108                if (object_class == null) {
109                        return false;
110                }
111                
112                // Gets a class's ifaces or an interface's super ifaces
113                Class[] ifaces = object_class.getInterfaces();
114                for (int i = 0; i < ifaces.length; i++) {
115                        if (isSameInterface(ifaces[i], iid)) {
116                                return findDispClassFromInterface(ifaces[i], out_class);
117                        }
118                        
119                        // recurse for super interfaces
120                        if (findDispClassForIID(ifaces[i], iid, out_class)) {
121                                return true;
122                        }
123                }
124                return false;
125        }
126        private static boolean isSameInterface(Class iface_class, GUID iid) {
127                Field[] fields = iface_class.getDeclaredFields();
128                for (int i = 0; i < fields.length; i++) {
129                        if (isSameInterface(iface_class, fields[i], iid)) {
130                                return true;
131                        }
132                }
133                return false;
134        }
135        private static boolean isSameInterface(Class iface_class, Field field, GUID iid) {
136                if (!field.getName().equals("IID")) {
137                        return false;
138                }
139                try {
140                        GUID iid_check = (GUID)iface_class.getField("IID").get(null);
141                        return iid_check.equals(iid);
142                } catch (Exception e) {
143                        throw new RuntimeException(e);
144                }
145        }
146        private static boolean findDispClassFromInterface(Class iface_class, Class[] out_class) {
147                Class[] classes = iface_class.getDeclaredClasses();
148                for (int i = 0; i < classes.length; i++) {
149                        if (classes[i].getName().endsWith("$Disp")) {
150                                out_class[0] = classes[i];
151                                return true;
152                        }
153                }
154                
155                throw new COMException(
156                                "Found IID, but missing Disp inner class, iface_class="
157                                                + iface_class, HRESULT.E_NOINTERFACE);
158        }
159        
160        public boolean isMatch(int disp_id, short invkind) {
161                return m_disp_id == disp_id && m_invkind == invkind;
162        }
163 
164        /**
165         * Call underlying Java method.
166         * 
167         * @param target
168         * @param args
169         * @return result of invoking the java method.
170         * @throws IllegalArgumentException
171         * @throws IllegalAccessException
172         * @throws InvocationTargetException
173         */
174        public Object invoke(Object target, Object[] args)
175                        throws IllegalArgumentException, IllegalAccessException,
176                        InvocationTargetException {
177                return m_java_method.invoke(target, args);
178        }
179 
180        /**
181         * @return dispatch id
182         */
183        public int getDispId() {
184                return m_disp_id;
185        }
186        
187        /**
188         * @return invocation kind
189         */
190        public short getInvKind() {
191                return m_invkind;
192        }
193 
194        /**
195         * @return Java method's reflected Method
196         */
197        public Method getJavaMethod() {
198                return m_java_method;
199        }
200 
201        /**
202         * @return Java method name.
203         */
204        public String getMethodName() {
205                return m_method_name;
206        }
207        
208        /**
209         * @return Java method's JNI signature.
210         */
211        public String getMethodSig() {
212                return m_method_sig;
213        }
214 
215        /**
216         * Fill in the Java Method for this mapping if not already filled in.
217         * 
218         * @param iface_class
219         * @throws NoSuchMethodException
220         */
221        public void fillInMethod(Class iface_class) throws NoSuchMethodException {
222                if (m_java_method != null) {
223                        return;
224                }
225                m_java_method = getMethod(iface_class, m_method_name, m_method_sig);
226        }
227 
228        /**
229         * Support looking up a method by name and JNI signature from java.
230         * 
231         * @param iface_class
232         * @param name
233         * @param jni_signature
234         * @return the found Method
235         * @throws NoSuchMethodException
236         */
237        static Method getMethod(Class iface_class, String name, String jni_signature)
238                        throws NoSuchMethodException {
239                return jni_getMethod(iface_class, name, jni_signature);
240        }
241 
242        private static native Method jni_getMethod(Class iface_class, String name,
243                        String jni_signature) throws NoSuchMethodException;
244 
245        private int m_disp_id;
246        private short m_invkind;
247        private Method m_java_method;
248        private String m_method_name;
249        private String m_method_sig;
250}

[all classes][com.moesol.bindings]
EMMA 2.0.5312 (C) Vladimir Roubtsov