package org.societies.comm.android.ipc; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; import android.os.Bundle; import android.os.Message; import android.os.Messenger; import android.os.Parcel; import android.os.Parcelable; class MessageMethodInvocation { private static final String KEY_ID = "id", KEY_CALLER = "caller", KEY_NAME = "name", KEY_PARAMS = "params", KEY_CALLBACK = "callback"; public static final int WHAT = 1; private String id; private String callerId; private String name; private Object[] params; private Class<?> callback = null; private Message msg; public MessageMethodInvocation(String callerId, String methodName, Object[] params, Messenger replyTo) { id = UUID.randomUUID().toString(); this.callerId = callerId; name = methodName; this.params = params; Bundle data = new Bundle(); data.putString(KEY_ID, id); data.putString(KEY_CALLER, callerId); data.putString(KEY_NAME, methodName); data.putParcelable(KEY_PARAMS, new Params(params)); msg = Message.obtain(null, WHAT); msg.replyTo = replyTo; msg.setData(data); } public MessageMethodInvocation(String callerId, String methodName, Object[] params, Class<?> callbackInterface, Messenger replyTo) { this(callerId, methodName, params, replyTo); this.callback = callbackInterface; msg.getData().putSerializable(KEY_CALLBACK, callbackInterface); } public MessageMethodInvocation(Message message) { msg = message; Bundle data = message.getData(); data.setClassLoader(MessageMethodInvocation.class.getClassLoader()); id = data.getString(KEY_ID); callerId = data.getString(KEY_CALLER); name = data.getString(KEY_NAME); params = ((Params)data.getParcelable(KEY_PARAMS)).params(); if(data.containsKey(KEY_CALLBACK)) callback = (Class<?>)data.getSerializable(KEY_CALLBACK); } public String id() { return id; } public String callerId() { return callerId; } public String name() { return name; } public Class<?>[] parameterTypes() { List<Class<?>> rv = new ArrayList<Class<?>>(); for(int i=0; i<params.length; i++) { if(params[i] == null) rv.add(null); else rv.add(params[i].getClass()); } if(hasCallback()) rv.add(callback); return rv.toArray(new Class<?>[0]); } public Object[] params() { return params; } public Object[] params(String callerId, Messenger replyTo) { List<Object> rv = new ArrayList<Object>(params.length+1); rv.addAll(Arrays.asList(params)); rv.add(Stub.newInstance(callback.getInterfaces(), callerId, replyTo)); return rv.toArray(); } public boolean hasCallback() { return callback != null; } public Class<?> callbackInterface() { return callback; } public Message message() { return msg; } public Method getMethod(Class<?> target) throws NoSuchMethodException { Class<?>[] methodParameterTypes = parameterTypes(); for (Method method : target.getMethods()) { Class<?>[] parameterTypes = method.getParameterTypes(); if (!method.getName().equals(name) || parameterTypes.length != methodParameterTypes.length) { continue; } boolean matches = true; for (int i = 0; i < parameterTypes.length; i++) { if (methodParameterTypes[i] != null && !parameterTypes[i].isAssignableFrom(methodParameterTypes[i])) { matches = false; break; } } if (matches) { return method; } } throw new NoSuchMethodException(); } private static class Params implements Parcelable { private Object[] params; public Params(Object[] params) { this.params = params; } public Object[] params() { return params; } public int describeContents() { return 0; } public void writeToParcel(Parcel out, int flags) { out.writeArray(params); } public static final Parcelable.Creator<Params> CREATOR = new Parcelable.Creator<Params>() { public Params createFromParcel(Parcel in) { return new Params(in); } public Params[] newArray(int size) { return new Params[size]; } }; private Params(Parcel in) { params = in.readArray(Params.class.getClassLoader()); } } }