Skip to main content
summaryrefslogtreecommitdiffstats
blob: 93d576d6d3ba6c73a668821c2694fa9b9dece441 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
/****************************************************************************
* Copyright (c) 2004 Composent, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    Composent, Inc. - initial API and implementation
*****************************************************************************/

package org.eclipse.ecf.example.collab.share;

import java.io.NotSerializableException;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import org.eclipse.ecf.core.identity.ID;

public class SharedObjectMsg implements Serializable {
    static final long serialVersionUID = 571132189626558278L;
    public static final Object[] nullArgs = new Object[0];
    public static final Class[] nullTypes = new Class[0];

    // Static factory methods for creating SharedObjectMsg instances
    public static SharedObjectMsg createMsg(String className, String methodName,
            Object[] param) {
        if (methodName == null || param == null) {
            throw new NullPointerException(
                    "Invalid SharedObjectMsg construction");
        }
        return new SharedObjectMsg(className, methodName, param);
    }

    public static SharedObjectMsg createMsg(String methodName, Object[] param) {
        return createMsg((String) null, methodName, param);
    }

    public static SharedObjectMsg createMsg(String methodName) {
        return createMsg((String) null, methodName, nullArgs);
    }

    public static SharedObjectMsg createMsg(String className, String methodName) {
        return createMsg(className, methodName, nullArgs);
    }

    public static SharedObjectMsg createMsg(String className, String methodName,
            Object arg) {
        Object args[] = { arg };
        return createMsg(className, methodName, args);
    }

    public static SharedObjectMsg createMsg(String methodName, Object arg) {
        return createMsg((String) null, methodName, arg);
    }

    public static SharedObjectMsg createMsg(String className, String methodName,
            Object arg1, Object arg2) {
        Object args[] = { arg1, arg2 };
        return createMsg(className, methodName, args);
    }

    public static SharedObjectMsg createMsg(String className, String methodName,
            Object arg1, Object arg2, Object arg3) {
        Object args[] = { arg1, arg2, arg3 };
        return createMsg(className, methodName, args);
    }

    public static SharedObjectMsg createMsg(String className, String methodName,
            Object arg1, Object arg2, Object arg3, Object arg4) {
        Object args[] = { arg1, arg2, arg3, arg4 };
        return createMsg(className, methodName, args);
    }

    public static SharedObjectMsg createMsg(String className, String methodName,
            Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) {
        Object args[] = { arg1, arg2, arg3, arg4, arg5 };
        return createMsg(className, methodName, args);
    }

    /**
     * Utility for getting a Class instance from a String class name. Calls
     * Class.forName().
     * 
     * @param loader
     *            the ClassLoader to use to load the given class
     * @param name
     *            of Class to load
     * @return Class instance found. If not found, a ClassNotFoundException is
     *         thrown
     * @exception ClassNotFoundException
     *                thrown if specified class is not found
     */
    public static Class getClass(ClassLoader loader, String name)
            throws ClassNotFoundException {
        if (name == null)
            return null;
        return Class.forName(name, true, loader);
    }

    /**
     * Get name for given class.
     * 
     * @param clazz
     *            the Class to retrieve the name from
     * @return String name of given class
     */
    public static String getName(Class clazz) {
        return clazz.getName();
    }

    /**
     * Get array of argument types from array of objects
     * 
     * @param args
     *            the arguments to get types for
     * @return Class[] of types for objects in given Object array
     */
    public static Class[] getArgTypes(Object args[]) {
        Class argTypes[] = null;
        if (args == null || args.length == 0)
            argTypes = nullTypes;
        else {
            argTypes = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                if (args[i] == null)
                    argTypes[i] = null;
                else
                    argTypes[i] = args[i].getClass();
            }
        }
        return argTypes;
    }

    /**
     * Find a Method instance on given class. This method searches for a method
     * on the given class (first parameter), of the given name (second
     * parameter), and of arity defined by the third parameter. Calls
     * searchForMethod to actually do the searching.
     * 
     * @param clazz
     *            the Class to look on
     * @param meth
     *            the method name to look for
     * @param args
     *            the arguments that will be passed to the method on the invoke
     *            call
     * @return Method instance found on given class. Null if none found.
     */
    static Method findMethod(final Class clazz, String meth, Class args[]) {
        Method methods[] = null;
        try {
            methods = (Method[]) AccessController
                    .doPrivileged(new PrivilegedExceptionAction() {
                        public Object run() throws Exception {
                            return clazz.getDeclaredMethods();
                        }
                    });
        } catch (PrivilegedActionException e) {
            return null;
        }
        return searchForMethod(methods, meth, args);
    }

    public static Method searchForMethod(Method meths[], String meth,
            Class args[]) {
        // Find it from among the given set of Method objects
        for (int i = 0; i < meths.length; i++) {
            Method test = meths[i];
            if (test.getName().equals(meth)) {
                if (test.getParameterTypes().length == args.length)
                    return test;
            }
        }
        return null;
    }

    /**
     * Find a Method instance on given class, and recursively search the class'
     * superclass tree for given method.
     * 
     * @param clazz
     *            the Class to look upon
     * @param meth
     *            the String name of the method to look for
     * @param args
     *            the array of Object arguments that will be passed to the
     *            method for execution
     * @return Method instance if found, null if not found
     */
    public static Method findMethodRecursive(Class clazz, String meth,
            Class args[]) {
        Method aMethod = findMethod(clazz, meth, args);
        if (aMethod == null) {
            Class superclazz = clazz.getSuperclass();
            if (superclazz != null)
                return findMethodRecursive(superclazz, meth, args);
            else
                return null;
        } else {
            return aMethod;
        }
    }

    /**
     * Check a given msg to verify that all Objects in args array implement the
     * Serializable interface.
     * 
     * @param aMsg
     *            the Message to check
     * @exception NotSerializableException
     *                thrown if any objects in args array do not implement the
     *                Serializable interface
     */
    public static void checkForSerializable(SharedObjectMsg aMsg)
            throws NotSerializableException {
        Object args[] = aMsg.getArgs();
        for (int i = 0; i < args.length; i++) {
            if (args[i] != null && !(args[i] instanceof Serializable))
                throw new NotSerializableException("Parameter " + i
                        + " not Serializable");
        }
    }

    // Instance fields
    /**
     * @serial myClassName the class name for the message
     */
    String myClassName;
    /**
     * @serial myMethodName the method name of the message
     */
    String myMethodName;
    /**
     * @serial myArgs arguments
     */
    Object[] myArgs;

    // Constructor
    SharedObjectMsg(String className, String methodName, Object[] args) {
        myClassName = className;
        myMethodName = methodName;
        myArgs = args;
    }

    /**
     * Constructor for TypedMsg's.
     */
    SharedObjectMsg(String methodName) {
        this(null, methodName, null);
    }

    public final String getMethodName() {
        return myMethodName;
    }

    public final void setMethodName(String name) {
        checkAlterMsg();
        if (name == null)
            throw new NullPointerException("methodname cannot be null");
        myMethodName = name;
    }

    /**
     * Check if it is permitted to alter the state of this message (args, class
     * name, method name). Default: NOP; subclasses should override as
     * appropriate. To disallow, throw a java.lang.RuntimeException.
     */
    protected void checkAlterMsg() {
        // NOP; subclasses should override as appropriate
    }

    public final String getClassName() {
        return myClassName;
    }

    public final void setClassName(String name) {
        checkAlterMsg();
        myClassName = name;
    }

    public Object[] getArgs() // TypedMsg overrides
    {
        return myArgs;
    }

    public final void setArgs(Object[] args) {
        checkAlterMsg();
        myArgs = (args == null) ? nullArgs : args;
    }

    protected Class[] getArgTypes() {
        return getArgTypes(getArgs());
    }

    protected final Method findMethod(Class clazz) {
        return findMethod(clazz, getMethodName(), getArgTypes());
    }

    protected final Method findMethodRecursive(Class clazz) {
        return findMethodRecursive(clazz, getMethodName(), getArgTypes());
    }

    public final Object invoke(Object target) throws Exception {
        return doInvoke(target);
    }

    Object doInvoke(final Object target) // package scope for security
            throws Exception {
        if (target == null)
            throw new NoSuchMethodException("Null target");
        Method meth = null;
        if (myClassName == null) {
            // If not specific class is specified by SharedObjectMsg instance,
            // then use the target's class
            meth = findMethodRecursive(target.getClass());
        } else {
            // If it is specified, then load the specified class, using the
            // target object's classloader
            meth = findMethod(getClass(target.getClass().getClassLoader(),
                    myClassName));
        }
        // If no method was found, then throw
        if (meth == null)
            throw new NoSuchMethodException(getMethodName());
        final Method toCall = meth;
        // Make priveleged call to set the method as accessible
        AccessController.doPrivileged(new PrivilegedExceptionAction() {
            public Object run() throws Exception {
                if (!toCall.isAccessible())
                    toCall.setAccessible(true);
                return null;
            }
        });
        // Actually invoke method
        return toCall.invoke(target, getArgs());
    }

    public final Object invokeFrom(ID fromID, final Object target)
            throws Exception {
        // Setup new array of arguments with the fromID on the front
        Object[] newParams = null;
        SenderID sender = new SenderID(fromID);
        Object args[] = getArgs();
        if (args == null) {
            newParams = new Object[1];
            newParams[0] = sender;
        } else {
            newParams = new Object[myArgs.length + 1];
            newParams[0] = sender;
            System.arraycopy(args, 0, newParams, 1, args.length);
        }
        // Reset arguments before method search
        myArgs = newParams;
        // Now just call invoke/1
        return invoke(target);
    }

    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("SharedObjectMsg[").append(myClassName).append(":").append(
                myMethodName).append("(");
        if (myArgs == null) {
            sb.append(myArgs);
        } else {
            for (int i = 0; i < myArgs.length; i++) {
                if (i > 0)
                    sb.append(",");
                sb.append(myArgs[i]);
            }
        }
        sb.append(")]");
        return sb.toString();
    }
}

Back to the top