package net.cattaka.util.cathandsgendroid.test.asyncif;
import java.util.HashMap;
import java.util.Map;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Handler.Callback;
import net.cattaka.util.cathandsgendroid.exception.AsyncInterfaceException;
import net.cattaka.util.cathandsgendroid.test.asyncif.SimpleInterface;
public class SimpleInterfaceAsync implements SimpleInterface {
private static final int WORK_SIZE = 6;
private static final int POOL_SIZE = 10;
private static final int EVENT_START = 1;
private static final int EVENT_METHOD_0_run = EVENT_START + 1;
private static final int EVENT_METHOD_1_add = EVENT_START + 2;
private static Callback sCallback = new Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case EVENT_METHOD_0_run: {
Object[] work = (Object[]) msg.obj;
SimpleInterfaceAsync me = (SimpleInterfaceAsync) work[0];
SimpleInterface orig = (SimpleInterface) work[1];
orig.run();
me.recycle(work);
return true;
}
case EVENT_METHOD_1_add: {
Object[] work = (Object[]) msg.obj;
SimpleInterface orig = (SimpleInterface) work[1];
Integer arg0 = (Integer) (work[0+2]);
Integer arg1 = (Integer) (work[1+2]);
try {
Object result =
orig.add(arg0 ,arg1);
work[WORK_SIZE - 2] = result;
} catch (Exception e) {
work[WORK_SIZE - 1] = e;
}
synchronized (work) {
work.notify();
}
return true;
}
}
return false;
}
};
private static Map<Looper, Handler> sHandlerMap = new HashMap<Looper, Handler>();
private Handler mHandler;
private Object[][] sOwnedPool = new Object[POOL_SIZE][WORK_SIZE];
private SimpleInterface orig;
public SimpleInterfaceAsync(SimpleInterface orig, Looper looper) {
super();
this.orig = orig;
synchronized (sHandlerMap) {
mHandler = sHandlerMap.get(looper);
if (mHandler == null) {
mHandler = new Handler(looper, sCallback);
sHandlerMap.put(looper, mHandler);
}
}
}
public SimpleInterfaceAsync(SimpleInterface orig) {
this(orig, Looper.getMainLooper());
}
@Override
public void run()
{
if (Looper.myLooper() == mHandler.getLooper()) {
orig.run();
return;
}
Object[] work = obtain();
work[0] = this;
work[1] = orig;
mHandler.obtainMessage(EVENT_METHOD_0_run, work).sendToTarget();
}
@Override
public int add(int arg0, int arg1)
{
if (Looper.myLooper() == mHandler.getLooper()) {
return orig.add(arg0, arg1);
}
Object[] work = obtain();
work[0] = this;
work[1] = orig;
work[0+2] = arg0;
work[1+2] = arg1;
synchronized (work) {
mHandler.obtainMessage(EVENT_METHOD_1_add, work)
.sendToTarget();
try {
work.wait();
} catch (InterruptedException e) {
throw new AsyncInterfaceException(e);
}
}
if (work[WORK_SIZE - 1] != null) {
throw new AsyncInterfaceException((Exception) work[WORK_SIZE - 1]);
}
int result = (Integer) work[WORK_SIZE - 2];
recycle(work);
return result;
}
private Object[] obtain() {
final Object[][] pool = sOwnedPool;
synchronized (pool) {
Object[] p;
for (int i = 0; i < POOL_SIZE; i++) {
p = pool[i];
if (p != null) {
pool[i] = null;
return p;
}
}
}
return new Object[WORK_SIZE];
}
private void recycle(Object[] p) {
for (int i=0;i<p.length;i++) {
p[i] = null;
}
final Object[][] pool = sOwnedPool;
synchronized (pool) {
for (int i = 0; i < POOL_SIZE; i++) {
if (pool[i] == null) {
pool[i] = p;
return;
}
}
}
}
}