aboutsummaryrefslogtreecommitdiffstats
path: root/AndroidAsync/src/com/koushikdutta/async/PushParser.java
diff options
context:
space:
mode:
authorZbigniew Szymański <zbigniew.szymanski@wearezeta.com>2014-03-29 21:12:29 +0100
committerZbigniew Szymański <zbigniew.szymanski@wearezeta.com>2014-03-29 21:30:30 +0100
commit720044511249c8ad85b986a0ea1c8a7cd8ab38ea (patch)
treea999e9bbdb27343bb06a52acb8ff300879b2d1fa /AndroidAsync/src/com/koushikdutta/async/PushParser.java
parent8992ab64d98dedbcdb746ccf7d8d9dd49c5c6acb (diff)
downloadAndroidAsync-720044511249c8ad85b986a0ea1c8a7cd8ab38ea.tar.gz
AndroidAsync-720044511249c8ad85b986a0ea1c8a7cd8ab38ea.tar.bz2
AndroidAsync-720044511249c8ad85b986a0ea1c8a7cd8ab38ea.zip
PushParser refactoring
- simplified implementation, removed couple unused methods - type safe TapCallback - no need for reflection, no problems with proguard
Diffstat (limited to 'AndroidAsync/src/com/koushikdutta/async/PushParser.java')
-rw-r--r--AndroidAsync/src/com/koushikdutta/async/PushParser.java347
1 files changed, 97 insertions, 250 deletions
diff --git a/AndroidAsync/src/com/koushikdutta/async/PushParser.java b/AndroidAsync/src/com/koushikdutta/async/PushParser.java
index aa41754..784729f 100644
--- a/AndroidAsync/src/com/koushikdutta/async/PushParser.java
+++ b/AndroidAsync/src/com/koushikdutta/async/PushParser.java
@@ -1,282 +1,129 @@
package com.koushikdutta.async;
-import android.util.Log;
-
import com.koushikdutta.async.callback.DataCallback;
-import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.util.ArrayList;
-import java.util.Hashtable;
import java.util.LinkedList;
-public class PushParser {
- private LinkedList<Object> mWaiting = new LinkedList<Object>();
+public class PushParser implements DataCallback {
- static class BufferWaiter {
+ static abstract class Waiter {
int length;
+ /**
+ * Consumes received data, and/or returns next waiter to continue reading instead of this waiter.
+ * @param bb received data, bb.remaining >= length
+ * @return - a waiter that should continue reading right away, or null if this waiter is finished
+ */
+ public abstract Waiter onDataAvailable(DataEmitter emitter, ByteBufferList bb);
+ }
+
+ static class IntWaiter extends Waiter {
+ TapCallback<Integer> callback;
+ public IntWaiter(TapCallback<Integer> callback) {
+ this.callback = callback;
+ this.length = 4;
+ }
+
+ @Override
+ public Waiter onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
+ callback.tap(bb.getInt());
+ return null;
+ }
}
-
- static class StringWaiter extends BufferWaiter {
+
+ static class BufferWaiter extends Waiter {
+ TapCallback<byte[]> callback;
+ public BufferWaiter(int length, TapCallback<byte[]> callback) {
+ if (length <= 0) throw new IllegalArgumentException("length should be > 0");
+ this.length = length;
+ this.callback = callback;
+ }
+
+ @Override
+ public Waiter onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
+ byte[] bytes = new byte[length];
+ bb.get(bytes);
+ callback.tap(bytes);
+ return null;
+ }
}
-
- static class UntilWaiter {
+
+ static class UntilWaiter extends Waiter {
+
byte value;
DataCallback callback;
- }
-
- int mNeeded = 0;
- public PushParser readInt() {
- mNeeded += 4;
- mWaiting.add(int.class);
- return this;
- }
+ public UntilWaiter(byte value, DataCallback callback) {
+ this.length = 1;
+ this.value = value;
+ this.callback = callback;
+ }
- public PushParser readByte() {
- mNeeded += 1;
- mWaiting.add(byte.class);
- return this;
- }
-
- public PushParser readShort() {
- mNeeded += 2;
- mWaiting.add(short.class);
- return this;
- }
-
- public PushParser readLong() {
- mNeeded += 8;
- mWaiting.add(long.class);
- return this;
- }
-
- public PushParser readBuffer(int length) {
- if (length != -1)
- mNeeded += length;
- BufferWaiter bw = new BufferWaiter();
- bw.length = length;
- mWaiting.add(bw);
- return this;
- }
+ @Override
+ public Waiter onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
+ boolean found = true;
+ ByteBufferList cb = new ByteBufferList();
+ while (bb.size() > 0) {
+ ByteBuffer b = bb.remove();
+ b.mark();
+ int index = 0;
+ while (b.remaining() > 0 && !(found = (b.get() == value))) {
+ index++;
+ }
+ b.reset();
+ if (found) {
+ bb.addFirst(b);
+ bb.get(cb, index);
+ // eat the one we're waiting on
+ bb.get();
+ break;
+ } else {
+ cb.add(b);
+ }
+ }
+
+ callback.onDataAvailable(emitter, cb);
+
+ if (found) {
+ return null;
+ } else {
+ return this;
+ }
+ }
- public PushParser readLenBuffer() {
- readInt();
- BufferWaiter bw = new BufferWaiter();
- bw.length = -1;
- mWaiting.add(bw);
- return this;
- }
-
- public PushParser readString() {
- readInt();
- StringWaiter bw = new StringWaiter();
- bw.length = -1;
- mWaiting.add(bw);
- return this;
- }
-
- public PushParser until(byte b, DataCallback callback) {
- UntilWaiter waiter = new UntilWaiter();
- waiter.value = b;
- waiter.callback = callback;
- mWaiting.add(waiter);
- mNeeded++;
- return this;
- }
-
- public PushParser noop() {
- mWaiting.add(Object.class);
- return this;
}
- DataEmitterReader mReader;
DataEmitter mEmitter;
+ private LinkedList<Waiter> mWaiting = new LinkedList<Waiter>();
+ ByteOrder order = ByteOrder.BIG_ENDIAN;
+
public PushParser(DataEmitter s) {
mEmitter = s;
- mReader = new DataEmitterReader();
- mEmitter.setDataCallback(mReader);
- }
-
- private ArrayList<Object> mArgs = new ArrayList<Object>();
- private TapCallback mCallback;
-
- Exception stack() {
- try {
- throw new Exception();
- }
- catch (Exception e) {
- return e;
- }
+ mEmitter.setDataCallback(this);
}
-
- ByteOrder order = ByteOrder.BIG_ENDIAN;
- public ByteOrder order() {
- return order;
- }
- public PushParser order(ByteOrder order) {
- this.order = order;
+
+ public PushParser readInt(TapCallback<Integer> callback) {
+ mWaiting.add(new IntWaiter(callback));
return this;
}
-
- public void tap(TapCallback callback) {
- assert mCallback == null;
- assert mWaiting.size() > 0;
- mCallback = callback;
-
- new DataCallback() {
- {
- onDataAvailable(mEmitter, null);
- }
-
- @Override
- public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
- try {
- if (bb != null)
- bb.order(order);
- while (mWaiting.size() > 0) {
- Object waiting = mWaiting.peek();
- if (waiting == null)
- break;
-// System.out.println("Remaining: " + bb.remaining());
- if (waiting == int.class) {
- mArgs.add(bb.getInt());
- mNeeded -= 4;
- }
- else if (waiting == short.class) {
- mArgs.add(bb.getShort());
- mNeeded -= 2;
- }
- else if (waiting == byte.class) {
- mArgs.add(bb.get());
- mNeeded -= 1;
- }
- else if (waiting == long.class) {
- mArgs.add(bb.getLong());
- mNeeded -= 8;
- }
- else if (waiting == Object.class) {
- mArgs.add(null);
- }
- else if (waiting instanceof UntilWaiter) {
- UntilWaiter uw = (UntilWaiter)waiting;
- boolean different = true;
- ByteBufferList cb = new ByteBufferList();
- while (bb.size() > 0) {
- ByteBuffer b = bb.remove();
- b.mark();
- int index = 0;
- while (b.remaining() > 0 && (different = (b.get() != uw.value))) {
- index++;
- }
- b.reset();
- if (!different) {
- bb.addFirst(b);
- bb.get(cb, index);
- // eat the one we're waiting on
- bb.get();
- break;
- }
- else {
- cb.add(b);
- }
- }
-
- if (uw.callback != null)
- uw.callback.onDataAvailable(emitter, cb);
+ public PushParser readBuffer(int length, TapCallback<byte[]> callback) {
+ mWaiting.add(new BufferWaiter(length, callback));
+ return this;
+ }
- if (!different) {
- mNeeded--;
- }
- else {
- throw new Exception();
- }
- }
- else if (waiting instanceof BufferWaiter || waiting instanceof StringWaiter) {
- BufferWaiter bw = (BufferWaiter)waiting;
- int length = bw.length;
- if (length == -1) {
- length = (Integer)mArgs.get(mArgs.size() - 1);
- mArgs.remove(mArgs.size() - 1);
- bw.length = length;
- mNeeded += length;
- }
- if (bb.remaining() < length) {
-// System.out.print("imminient feilure detected");
- throw new Exception();
- }
-
-// e.printStackTrace();
-// System.out.println("Buffer length: " + length);
- byte[] bytes = null;
- if (length > 0) {
- bytes = new byte[length];
- bb.get(bytes);
- }
- mNeeded -= length;
- if (waiting instanceof StringWaiter)
- mArgs.add(new String(bytes));
- else
- mArgs.add(bytes);
- }
- else {
- assert false;
- }
-// System.out.println("Parsed: " + mArgs.get(0));
- mWaiting.remove();
- }
- }
- catch (Exception ex) {
- assert mNeeded != 0;
-// ex.printStackTrace();
- mReader.read(mNeeded, this);
- return;
- }
-
- try {
- Object[] args = mArgs.toArray();
- mArgs.clear();
- TapCallback callback = mCallback;
- mCallback = null;
- Method method = getTap(callback);
- method.setAccessible(true);
- method.invoke(callback, args);
- }
- catch (Exception ex) {
- assert false;
- Log.e("PushParser", "error during parse", ex);
- }
- }
- };
+ public PushParser until(byte b, DataCallback callback) {
+ mWaiting.add(new UntilWaiter(b, callback));
+ return this;
}
- static Hashtable<Class, Method> mTable = new Hashtable<Class, Method>();
- static Method getTap(TapCallback callback) {
- Method found = mTable.get(callback.getClass());
- if (found != null)
- return found;
+ @Override
+ public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
- for (Method method : callback.getClass().getMethods()) {
- if ("tap".equals(method.getName())) {
- mTable.put(callback.getClass(), method);
- return method;
- }
+ while (mWaiting.size() > 0 && bb.remaining() >= mWaiting.peek().length) {
+ bb.order(order);
+ Waiter next = mWaiting.poll().onDataAvailable(emitter, bb);
+ if (next != null) mWaiting.addFirst(next);
}
-
- // try the proguard friendly route, take the first/only method
- // in case "tap" has been renamed
- Method[] candidates = callback.getClass().getDeclaredMethods();
- if (candidates.length == 1)
- return candidates[0];
-
- String fail =
- "-keep class * extends com.koushikdutta.async.TapCallback {\n" +
- " *;\n" +
- "}\n";
-
- //null != "AndroidAsync: tap callback could not be found. Proguard? Use this in your proguard config:\n" + fail;
- assert false;
- return null;
}
}