From 2d14a9eca1e621d7a4fc919f0ea04bc630611b89 Mon Sep 17 00:00:00 2001 From: "Lilli Szafranski (Jaguar - Land Rover)" Date: Mon, 1 Aug 2016 13:25:52 -0700 Subject: [PATCH 1/6] [RCA-19] ServerConnection line 280 catch all exceptions, not just IO (cherry picked from commit 7f2d26530558336d1a226918f3221464fb09db55) --- src/main/java/com/jaguarlandrover/rvi/RVINode.java | 1 - src/main/java/com/jaguarlandrover/rvi/ServerConnection.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/jaguarlandrover/rvi/RVINode.java b/src/main/java/com/jaguarlandrover/rvi/RVINode.java index 0bda8b2..7c63bf2 100644 --- a/src/main/java/com/jaguarlandrover/rvi/RVINode.java +++ b/src/main/java/com/jaguarlandrover/rvi/RVINode.java @@ -153,7 +153,6 @@ public void setServerPort(Integer serverPort) { mRemoteConnectionManager.setServerPort(serverPort); } - /** * Method to pass the SDK your app's JWT-encoded json credentials for invoking services on a remote node and receiving service invocations from a remote node. * diff --git a/src/main/java/com/jaguarlandrover/rvi/ServerConnection.java b/src/main/java/com/jaguarlandrover/rvi/ServerConnection.java index 09f869e..154cbd3 100644 --- a/src/main/java/com/jaguarlandrover/rvi/ServerConnection.java +++ b/src/main/java/com/jaguarlandrover/rvi/ServerConnection.java @@ -277,7 +277,7 @@ protected Throwable doInBackground(Void... params) { wr.writeBytes(data); wr.flush(); - } catch (IOException e) { + } catch (Exception e) { e.printStackTrace(); return e; From 62253c0a705f7071f072e6b04468df9d30b33e37 Mon Sep 17 00:00:00 2001 From: "Lilli Szafranski (Jaguar - Land Rover)" Date: Wed, 28 Sep 2016 14:50:28 -0700 Subject: [PATCH 2/6] [RCA-38] When sending a service invocation, service object is copied into dlink packet so subsequent invocations don't overwrite the parameters. (cherry picked from commit 3c8e5db8ce3825d43470eb58513c1969536fe7c2) --- .../com/jaguarlandrover/rvi/DlinkReceivePacket.java | 6 +----- src/main/java/com/jaguarlandrover/rvi/Service.java | 13 +++++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/jaguarlandrover/rvi/DlinkReceivePacket.java b/src/main/java/com/jaguarlandrover/rvi/DlinkReceivePacket.java index 3edc91f..13ea3f1 100644 --- a/src/main/java/com/jaguarlandrover/rvi/DlinkReceivePacket.java +++ b/src/main/java/com/jaguarlandrover/rvi/DlinkReceivePacket.java @@ -59,11 +59,7 @@ class DlinkReceivePacket extends DlinkPacket super(Command.RECEIVE); mMod = "proto_json_rpc"; - mService = service; - - - // TODO: With this paradigm, if one of the parameters of mService changes, mData string will still be the same. - //mData = mService.jsonString();//Base64.encodeToString(mService.jsonString().getBytes(), Base64.DEFAULT); + mService = service.copy(); } // public DlinkReceivePacket(HashMap jsonHash) { diff --git a/src/main/java/com/jaguarlandrover/rvi/Service.java b/src/main/java/com/jaguarlandrover/rvi/Service.java index 2a49d7d..32f96d6 100644 --- a/src/main/java/com/jaguarlandrover/rvi/Service.java +++ b/src/main/java/com/jaguarlandrover/rvi/Service.java @@ -135,6 +135,10 @@ boolean hasNodeIdentifier() { return mNodeIdentifier != null; } + private String getNodeIdentifier() { + return mNodeIdentifier; + } + /** * Sets the node identifier portion of the fully-qualified service name * @@ -219,4 +223,13 @@ Long getTimeout() { void setTimeout(Long timeout) { mTimeout = timeout; } + + public Service copy() { + Service copy = new Service(this.getServiceIdentifier(), this.getDomain(), this.getBundleIdentifier(), this.getNodeIdentifier()); + + copy.setTimeout(this.getTimeout()); + copy.setParameters(this.getParameters()); + + return null; + } } From b5b91da962d899690034d2f6b33cc063ad7d0f40 Mon Sep 17 00:00:00 2001 From: "Lilli Szafranski (Jaguar - Land Rover)" Date: Wed, 28 Sep 2016 15:17:48 -0700 Subject: [PATCH 3/6] [RCA-39] Made it so that queued pending service invocations all go out all at once, as opposed to only sending the last-invoked invocation, in the order they were received. Changed all the network-related background thread execution to be serial to guarantee order stays correct. Not really tested though. (cherry picked from commit 993b0592d4bc10e6faf1245e8fed680d999899ff) --- .../rvi/BluetoothConnection.java | 6 ++-- .../jaguarlandrover/rvi/ServerConnection.java | 6 ++-- .../jaguarlandrover/rvi/ServiceBundle.java | 28 ++++++++++++++----- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/jaguarlandrover/rvi/BluetoothConnection.java b/src/main/java/com/jaguarlandrover/rvi/BluetoothConnection.java index ae10621..e74737b 100644 --- a/src/main/java/com/jaguarlandrover/rvi/BluetoothConnection.java +++ b/src/main/java/com/jaguarlandrover/rvi/BluetoothConnection.java @@ -54,7 +54,7 @@ public void sendRviRequest(DlinkPacket dlinkPacket) { if (!isConnected() || !isConfigured()) // TODO: Call error on listener return; - new SendDataTask(dlinkPacket).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);//, dlinkPacket.toJsonString()); + new SendDataTask(dlinkPacket).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);//, dlinkPacket.toJsonString()); } @Override @@ -97,7 +97,7 @@ private void connectSocket() { Log.d(TAG, "Connecting to device: " + mDeviceAddress + ":" + mServiceRecord + ":" + mChannel); ConnectTask connectAndAuthorizeTask = new ConnectTask(mDeviceAddress, mServiceRecord, mChannel); - connectAndAuthorizeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + connectAndAuthorizeTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); } private class ConnectTask extends AsyncTask @@ -186,7 +186,7 @@ protected void onPostExecute(Throwable result) { Log.d(TAG, "Connecting Bluetooth socket: Creating listener..."); ListenTask listenTask = new ListenTask(); - listenTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + listenTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); if (mRemoteConnectionListener != null) mRemoteConnectionListener.onRemoteConnectionDidConnect(); diff --git a/src/main/java/com/jaguarlandrover/rvi/ServerConnection.java b/src/main/java/com/jaguarlandrover/rvi/ServerConnection.java index 154cbd3..aa3497e 100644 --- a/src/main/java/com/jaguarlandrover/rvi/ServerConnection.java +++ b/src/main/java/com/jaguarlandrover/rvi/ServerConnection.java @@ -49,7 +49,7 @@ public void sendRviRequest(DlinkPacket dlinkPacket) { return; } - new SendDataTask(dlinkPacket).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);//, dlinkPacket.toJsonString()); + new SendDataTask(dlinkPacket).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);//, dlinkPacket.toJsonString()); } @Override @@ -93,7 +93,7 @@ private void connectSocket() { Log.d(TAG, "Connecting the socket: " + mServerUrl + ":" + mServerPort); ConnectTask connectAndAuthorizeTask = new ConnectTask(mServerUrl, mServerPort, mServerKeyStore, mClientKeyStore, mClientKeyStorePassword); - connectAndAuthorizeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + connectAndAuthorizeTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); } private class ConnectTask extends AsyncTask @@ -200,7 +200,7 @@ protected void onPostExecute(Throwable result) { if (result == null) { // TODO: Does the input buffer stream cache data in the case that my async thread sends the auth command before the listener is set up? ListenTask listenTask = new ListenTask(); - listenTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + listenTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); if (mRemoteConnectionListener != null) mRemoteConnectionListener.onRemoteConnectionDidConnect(); diff --git a/src/main/java/com/jaguarlandrover/rvi/ServiceBundle.java b/src/main/java/com/jaguarlandrover/rvi/ServiceBundle.java index 0e87867..d07eec0 100644 --- a/src/main/java/com/jaguarlandrover/rvi/ServiceBundle.java +++ b/src/main/java/com/jaguarlandrover/rvi/ServiceBundle.java @@ -18,6 +18,7 @@ import java.security.InvalidParameterException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; @@ -37,7 +38,7 @@ public class ServiceBundle private HashMap mRemoteServices = new HashMap<>(); - private HashMap mPendingServiceInvocations = new HashMap<>(); + private HashMap> mPendingServiceInvocations = new HashMap<>(); private RVINode mNode; /** @@ -174,11 +175,14 @@ void addRemoteService(String serviceIdentifier, String remoteNodeIdentifier) { if (!mRemoteServices.containsKey(serviceIdentifier)) mRemoteServices.put(serviceIdentifier, new Service(serviceIdentifier, mDomain, mBundleIdentifier, remoteNodeIdentifier)); - Service pendingServiceInvocation = mPendingServiceInvocations.get(serviceIdentifier); - if (pendingServiceInvocation != null) { - if (pendingServiceInvocation.getTimeout() >= System.currentTimeMillis()) { - pendingServiceInvocation.setNodeIdentifier(remoteNodeIdentifier); - mNode.invokeService(pendingServiceInvocation); + ArrayList pendingServiceInvocationList = mPendingServiceInvocations.get(serviceIdentifier); + + if (pendingServiceInvocationList != null) { + for (Service pendingServiceInvocation : pendingServiceInvocationList) { + if (pendingServiceInvocation.getTimeout() >= System.currentTimeMillis()) { + pendingServiceInvocation.setNodeIdentifier(remoteNodeIdentifier); + mNode.invokeService(pendingServiceInvocation); + } } mPendingServiceInvocations.remove(serviceIdentifier); @@ -200,6 +204,16 @@ void removeAllRemoteServices() { mRemoteServices.clear(); } + private void queueServiceInvocation(String serviceIdentifier, Service service) { + + ArrayList pendingServiceInvocationList = mPendingServiceInvocations.get(serviceIdentifier); + if (pendingServiceInvocationList != null) { + pendingServiceInvocationList.add(service.copy()); + } else { + mPendingServiceInvocations.put(serviceIdentifier, new ArrayList<>(Arrays.asList(service.copy()))); + } + } + /** * Invoke/update a remote service on the remote RVI node * @@ -216,7 +230,7 @@ public void invokeService(String serviceIdentifier, Object parameters, Integer t if (service.hasNodeIdentifier() && mNode != null) // TODO: Check the logic here mNode.invokeService(service); else - mPendingServiceInvocations.put(serviceIdentifier, service); + queueServiceInvocation(serviceIdentifier, service); } /** From e141e7a86ddcece047583f6db8fb2845ba828c9f Mon Sep 17 00:00:00 2001 From: "Lilli Szafranski (Jaguar - Land Rover)" Date: Thu, 29 Sep 2016 16:01:58 -0700 Subject: [PATCH 4/6] [RCA-38] Fixed bug where copy method was returning null instead of the copied object --- src/main/java/com/jaguarlandrover/rvi/Service.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/jaguarlandrover/rvi/Service.java b/src/main/java/com/jaguarlandrover/rvi/Service.java index 32f96d6..2364596 100644 --- a/src/main/java/com/jaguarlandrover/rvi/Service.java +++ b/src/main/java/com/jaguarlandrover/rvi/Service.java @@ -230,6 +230,6 @@ public Service copy() { copy.setTimeout(this.getTimeout()); copy.setParameters(this.getParameters()); - return null; + return copy; } } From 899e1b0b5dd0ee350b8eac07754a02e4c0eb8d80 Mon Sep 17 00:00:00 2001 From: "Lilli Szafranski (Jaguar - Land Rover)" Date: Tue, 4 Oct 2016 16:06:44 -0700 Subject: [PATCH 5/6] [RCA-39] Fixed bug where only send task should be serial, not connect or listen tasks --- src/main/java/com/jaguarlandrover/rvi/ServerConnection.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/jaguarlandrover/rvi/ServerConnection.java b/src/main/java/com/jaguarlandrover/rvi/ServerConnection.java index aa3497e..91f646e 100644 --- a/src/main/java/com/jaguarlandrover/rvi/ServerConnection.java +++ b/src/main/java/com/jaguarlandrover/rvi/ServerConnection.java @@ -93,7 +93,7 @@ private void connectSocket() { Log.d(TAG, "Connecting the socket: " + mServerUrl + ":" + mServerPort); ConnectTask connectAndAuthorizeTask = new ConnectTask(mServerUrl, mServerPort, mServerKeyStore, mClientKeyStore, mClientKeyStorePassword); - connectAndAuthorizeTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); + connectAndAuthorizeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } private class ConnectTask extends AsyncTask @@ -200,7 +200,7 @@ protected void onPostExecute(Throwable result) { if (result == null) { // TODO: Does the input buffer stream cache data in the case that my async thread sends the auth command before the listener is set up? ListenTask listenTask = new ListenTask(); - listenTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); + listenTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); if (mRemoteConnectionListener != null) mRemoteConnectionListener.onRemoteConnectionDidConnect(); From d56e8617011e3e03e14aca48dac949f35d08ce1f Mon Sep 17 00:00:00 2001 From: "Lilli Szafranski (Jaguar - Land Rover)" Date: Wed, 28 Sep 2016 11:34:29 -0700 Subject: [PATCH 6/6] [RUA-29] Catching json parse exceptions of dlink packets and added callbacks to interfaces for handling packet receive errors (cherry picked from commit e3dd49e7e8b6093654026b287a6ea94713b8afaf) --- .../rvi/DlinkPacketParser.java | 42 ++++++++++++------- .../java/com/jaguarlandrover/rvi/RVINode.java | 5 +++ .../rvi/RemoteConnectionManager.java | 5 +++ .../rvi/RemoteConnectionManagerListener.java | 7 ++++ 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/jaguarlandrover/rvi/DlinkPacketParser.java b/src/main/java/com/jaguarlandrover/rvi/DlinkPacketParser.java index 71cc71c..648d584 100644 --- a/src/main/java/com/jaguarlandrover/rvi/DlinkPacketParser.java +++ b/src/main/java/com/jaguarlandrover/rvi/DlinkPacketParser.java @@ -40,6 +40,14 @@ interface DlinkPacketParserListener * @param packet the dlink packet */ void onPacketParsed(DlinkPacket packet); + + /** + * Failed when trying to parse the packet. Callback method that notifies listener when a dlink packet was unable to + * be parsed out of the input stream coming from an rvi node over the network. + * + * @param error the error + */ + void onPacketFailedToParse(Throwable error); } /** @@ -110,26 +118,28 @@ private DlinkPacket stringToPacket(String string) { try { packet = gson.fromJson(string, DlinkPacket.class); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - if (mDataParserListener instanceof DlinkPacketParserTestCaseListener) - ((DlinkPacketParserTestCaseListener) mDataParserListener).onJsonObjectParsed(packet); + if (mDataParserListener instanceof DlinkPacketParserTestCaseListener) + ((DlinkPacketParserTestCaseListener) mDataParserListener).onJsonObjectParsed(packet); - DlinkPacket.Command command = packet.mCmd; + DlinkPacket.Command command = packet.mCmd; - if (command == null) - return null; + if (command == null) + return null; + + if (command == DlinkPacket.Command.AUTHORIZE) { + return gson.fromJson(string, DlinkAuthPacket.class); + } else if (command == DlinkPacket.Command.SERVICE_ANNOUNCE) { + return gson.fromJson(string, DlinkServiceAnnouncePacket.class); + } else if (command == DlinkPacket.Command.RECEIVE) { + return gson.fromJson(string, DlinkReceivePacket.class); + } else { + return null; + } + } catch (Exception e) { + e.printStackTrace(); + mDataParserListener.onPacketFailedToParse(e); - if (command == DlinkPacket.Command.AUTHORIZE) { - return gson.fromJson(string, DlinkAuthPacket.class); - } else if (command == DlinkPacket.Command.SERVICE_ANNOUNCE) { - return gson.fromJson(string, DlinkServiceAnnouncePacket.class); - } else if (command == DlinkPacket.Command.RECEIVE) { - return gson.fromJson(string, DlinkReceivePacket.class); - } else { return null; } } diff --git a/src/main/java/com/jaguarlandrover/rvi/RVINode.java b/src/main/java/com/jaguarlandrover/rvi/RVINode.java index 7c63bf2..4eb357c 100644 --- a/src/main/java/com/jaguarlandrover/rvi/RVINode.java +++ b/src/main/java/com/jaguarlandrover/rvi/RVINode.java @@ -87,6 +87,11 @@ public void onRVIDidReceivePacket(DlinkPacket packet) { } } + @Override + public void onRVIDidFailToReceivePacket(Throwable error) { + Log.d(TAG, Util.getMethodName() + ": " + ((error == null) ? "(null)" : error.getLocalizedMessage())); + } + @Override public void onRVIDidSendPacket(DlinkPacket packet) { if (packet == null) return; diff --git a/src/main/java/com/jaguarlandrover/rvi/RemoteConnectionManager.java b/src/main/java/com/jaguarlandrover/rvi/RemoteConnectionManager.java index ca6570f..c81144b 100644 --- a/src/main/java/com/jaguarlandrover/rvi/RemoteConnectionManager.java +++ b/src/main/java/com/jaguarlandrover/rvi/RemoteConnectionManager.java @@ -49,6 +49,11 @@ public enum ConnectionType public void onPacketParsed(DlinkPacket packet) { if (mListener != null) mListener.onRVIDidReceivePacket(packet); } + + @Override + public void onPacketFailedToParse(Throwable error) { + if (mListener != null) mListener.onRVIDidFailToReceivePacket(error); + } }); RemoteConnectionInterface.RemoteConnectionListener connectionListener = new RemoteConnectionInterface.RemoteConnectionListener() diff --git a/src/main/java/com/jaguarlandrover/rvi/RemoteConnectionManagerListener.java b/src/main/java/com/jaguarlandrover/rvi/RemoteConnectionManagerListener.java index 1212016..6806690 100644 --- a/src/main/java/com/jaguarlandrover/rvi/RemoteConnectionManagerListener.java +++ b/src/main/java/com/jaguarlandrover/rvi/RemoteConnectionManagerListener.java @@ -43,6 +43,13 @@ interface RemoteConnectionManagerListener // TODO: Get rid of this middle man */ void onRVIDidReceivePacket(DlinkPacket packet); + /** + * RVI did receive packet but there was an error with the packet. + * + * @param error the error + */ + void onRVIDidFailToReceivePacket(Throwable error); + /** * On RVI did send packet. */