From 1389b8323ff159b72ace6d7544c21afa16dd8544 Mon Sep 17 00:00:00 2001 From: dchurchland Date: Mon, 27 Feb 2017 16:50:05 +1100 Subject: [PATCH 001/211] re-authenticate before creating request to avoid 'already connected' error on POST --- .../client/JsonServiceClient.java | 11 ++++++--- .../servicestack/client/TestAuthTests.java | 24 +++++++++++++++---- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/JsonServiceClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/JsonServiceClient.java index 1d7be85d..7e1f59e4 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/JsonServiceClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/JsonServiceClient.java @@ -136,6 +136,11 @@ public String createUrl(Object requestDto, Map query){ } public HttpURLConnection createRequest(String requestUrl, String httpMethod, byte[] requestBody, String requestType) { + return createRequest(requestUrl, httpMethod, requestBody, requestType, false); + + } + + public HttpURLConnection createRequest(String requestUrl, String httpMethod, byte[] requestBody, String requestType, Boolean forceAuthentication) { try { URL url = new URL(requestUrl); @@ -153,7 +158,7 @@ public HttpURLConnection createRequest(String requestUrl, String httpMethod, byt req.setRequestProperty(HttpHeaders.ContentType, requestType); } - if (alwaysSendBasicAuthHeaders) { + if (forceAuthentication || alwaysSendBasicAuthHeaders) { addBasicAuth(req, userName, password); } @@ -336,8 +341,8 @@ public TResponse send(String requestUrl, String httpMethod, byte[] r if (shouldAuthenticate(req, userName, password)){ req.disconnect(); - req = createRequest(requestUrl, httpMethod, requestBody, requestType); - addBasicAuth(req, userName, password); + req = createRequest(requestUrl, httpMethod, requestBody, requestType, true); + success = req.getResponseCode() < 400; } diff --git a/src/AndroidClient/client/src/test/java/net/servicestack/client/TestAuthTests.java b/src/AndroidClient/client/src/test/java/net/servicestack/client/TestAuthTests.java index db8a6878..19c5a4ce 100644 --- a/src/AndroidClient/client/src/test/java/net/servicestack/client/TestAuthTests.java +++ b/src/AndroidClient/client/src/test/java/net/servicestack/client/TestAuthTests.java @@ -35,17 +35,33 @@ public void test_does_send_BasicAuthHeaders(){ assertNotNull(response.getSessionId()); } - public void test_does_transparently_send_BasicAuthHeader_on_401_response(){ + private void does_transparently_send_BasicAuthHeader_on_401(Boolean isPost){ ServiceClient client = CreateClient(); client.setCredentials("test", "test"); - - testdtos.TestAuthResponse response = client.get(new testdtos.TestAuth()); - + + testdtos.TestAuthResponse response = null; + if (isPost) { + response = client.post(new testdtos.TestAuth()); + } else { + response = client.get(new testdtos.TestAuth()); + } assertEquals("1", response.getUserId()); assertEquals("test", response.getUserName()); assertEquals("test DisplayName", response.getDisplayName()); assertNotNull(response.getSessionId()); } + + public void test_does_transparently_send_BasicAuthHeader_on_401_response_From_get(){ + + does_transparently_send_BasicAuthHeader_on_401( false); + + } + + public void test_does_transparently_send_BasicAuthHeader_on_401_response_from_post(){ + + does_transparently_send_BasicAuthHeader_on_401( true); + + } public void test_can_authenticate_with_CredentialsAuth(){ ServiceClient client = CreateClient(); From 12948e4325da516f9ee39e1eb08824ef44d07351 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Mon, 27 Feb 2017 15:19:26 -0500 Subject: [PATCH 002/211] sync PR --- .../net/servicestack/client/JsonServiceClient.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/JsonServiceClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/JsonServiceClient.java index 1d7be85d..7e1f59e4 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/JsonServiceClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/JsonServiceClient.java @@ -136,6 +136,11 @@ public String createUrl(Object requestDto, Map query){ } public HttpURLConnection createRequest(String requestUrl, String httpMethod, byte[] requestBody, String requestType) { + return createRequest(requestUrl, httpMethod, requestBody, requestType, false); + + } + + public HttpURLConnection createRequest(String requestUrl, String httpMethod, byte[] requestBody, String requestType, Boolean forceAuthentication) { try { URL url = new URL(requestUrl); @@ -153,7 +158,7 @@ public HttpURLConnection createRequest(String requestUrl, String httpMethod, byt req.setRequestProperty(HttpHeaders.ContentType, requestType); } - if (alwaysSendBasicAuthHeaders) { + if (forceAuthentication || alwaysSendBasicAuthHeaders) { addBasicAuth(req, userName, password); } @@ -336,8 +341,8 @@ public TResponse send(String requestUrl, String httpMethod, byte[] r if (shouldAuthenticate(req, userName, password)){ req.disconnect(); - req = createRequest(requestUrl, httpMethod, requestBody, requestType); - addBasicAuth(req, userName, password); + req = createRequest(requestUrl, httpMethod, requestBody, requestType, true); + success = req.getResponseCode() < 400; } From 67e96e86119ddf24a356f609ed438c15f393a6d9 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Mon, 27 Feb 2017 15:20:22 -0500 Subject: [PATCH 003/211] refactor ServerEventsClient so interrupting bgThread it will throw InterruptedException --- .../client/sse/ServerEventsClient.java | 38 +++++++++++++------ .../client/sse/ServerEventsClient.java | 38 +++++++++++++------ 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index ab85d57b..c4295305 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -16,6 +16,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.InterruptedIOException; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -274,11 +275,18 @@ public String getConnectionDisplayName() { : "(not connected)"; } - public ServerEventsClient start(){ + private synchronized void interruptBackgroundThread() { if (bgThread != null){ bgThread.interrupt(); + try { + bgThread.join(); + } catch (InterruptedException ignore) {} bgThread = null; } + } + + public ServerEventsClient start(){ + interruptBackgroundThread(); stopped.set(false); bgThread = new Thread(new EventStream(this)); @@ -359,10 +367,7 @@ private synchronized void internalStop() { } connectionInfo = null; - if (bgThread != null) - bgThread.interrupt(); - - bgThread = null; + interruptBackgroundThread(); } private void onCommandReceived(ServerEventMessage e) { @@ -564,26 +569,35 @@ public void run() { InputStream is = new BufferedInputStream(req.getInputStream()); errorsCount.set(0); readStream(is); - - running.set(false); + } catch (InterruptedException ie){ + Log.i("EventStream.run(): Caught InterruptedException"); //thrown by interruptBackgroundThread() + return; } catch (Exception e) { Log.e("Error reading from event-stream, continuous errors: " + errorsCount.incrementAndGet(), e); Log.e(Utils.getStackTrace(e)); - running.set(false); } finally { - if (!running.get()){ - client.restart(); - } + running.set(false); + } + + if (!running.get()){ + client.restart(); } } - private void readStream(InputStream inputStream) throws IOException { + private void readStream(InputStream inputStream) throws IOException, InterruptedException { byte[] buffer = new byte[BufferSize]; String overflowText = ""; int len = 0; while (true) { + while (true) { + int available = inputStream.available(); + if (available > 0) break; + Thread.sleep(5); + } + len = inputStream.read(buffer); + if (len <= 0) break; diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index ab85d57b..c4295305 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -16,6 +16,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.InterruptedIOException; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -274,11 +275,18 @@ public String getConnectionDisplayName() { : "(not connected)"; } - public ServerEventsClient start(){ + private synchronized void interruptBackgroundThread() { if (bgThread != null){ bgThread.interrupt(); + try { + bgThread.join(); + } catch (InterruptedException ignore) {} bgThread = null; } + } + + public ServerEventsClient start(){ + interruptBackgroundThread(); stopped.set(false); bgThread = new Thread(new EventStream(this)); @@ -359,10 +367,7 @@ private synchronized void internalStop() { } connectionInfo = null; - if (bgThread != null) - bgThread.interrupt(); - - bgThread = null; + interruptBackgroundThread(); } private void onCommandReceived(ServerEventMessage e) { @@ -564,26 +569,35 @@ public void run() { InputStream is = new BufferedInputStream(req.getInputStream()); errorsCount.set(0); readStream(is); - - running.set(false); + } catch (InterruptedException ie){ + Log.i("EventStream.run(): Caught InterruptedException"); //thrown by interruptBackgroundThread() + return; } catch (Exception e) { Log.e("Error reading from event-stream, continuous errors: " + errorsCount.incrementAndGet(), e); Log.e(Utils.getStackTrace(e)); - running.set(false); } finally { - if (!running.get()){ - client.restart(); - } + running.set(false); + } + + if (!running.get()){ + client.restart(); } } - private void readStream(InputStream inputStream) throws IOException { + private void readStream(InputStream inputStream) throws IOException, InterruptedException { byte[] buffer = new byte[BufferSize]; String overflowText = ""; int len = 0; while (true) { + while (true) { + int available = inputStream.available(); + if (available > 0) break; + Thread.sleep(5); + } + len = inputStream.read(buffer); + if (len <= 0) break; From 3f9bd633741b9e6b67cef3a8d2046492d2d0059a Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Wed, 1 Mar 2017 22:28:26 -0500 Subject: [PATCH 004/211] bump version to v1.0.28 --- src/AndroidClient/android/build.gradle | 2 +- src/AndroidClient/client/build.gradle | 2 +- src/AndroidClient/client/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AndroidClient/android/build.gradle b/src/AndroidClient/android/build.gradle index 1fd80353..b21c000f 100644 --- a/src/AndroidClient/android/build.gradle +++ b/src/AndroidClient/android/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'kotlin-android' apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' -version = "1.0.27" +version = "1.0.28" android { compileSdkVersion 24 diff --git a/src/AndroidClient/client/build.gradle b/src/AndroidClient/client/build.gradle index 48e5ca7f..d772f76c 100644 --- a/src/AndroidClient/client/build.gradle +++ b/src/AndroidClient/client/build.gradle @@ -11,7 +11,7 @@ dependencies { testCompile 'org.mockito:mockito-core:1.9.5' } -version = "1.0.27" +version = "1.0.28" group = "net.servicestack" // Maven Group ID for the artifact String packageId = "client" String groupID = group diff --git a/src/AndroidClient/client/pom.xml b/src/AndroidClient/client/pom.xml index f6f04817..3d49fee1 100644 --- a/src/AndroidClient/client/pom.xml +++ b/src/AndroidClient/client/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.servicestack client - 1.0.27 + 1.0.28 ServiceStack.Client A client library to call your ServiceStack webservices. https://github.com/ServiceStack/ServiceStack.Java From 0719f1936ff9bce20ff8c776e49c95745ff78d64 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Wed, 1 Mar 2017 22:28:37 -0500 Subject: [PATCH 005/211] Update proj files --- src/AndroidClient/android/android.iml | 2 ++ src/AndroidClient/androidchat/androidchat.iml | 4 ++-- src/AndroidClient/kotlin/kotlin.iml | 16 ++++++++-------- src/AndroidClient/techstacks/techstacks.iml | 16 ++++++++-------- .../techstackskotlin/techstackskotlin.iml | 16 ++++++++-------- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/AndroidClient/android/android.iml b/src/AndroidClient/android/android.iml index 0b9d5386..2341381c 100644 --- a/src/AndroidClient/android/android.iml +++ b/src/AndroidClient/android/android.iml @@ -84,6 +84,7 @@ + @@ -93,6 +94,7 @@ + diff --git a/src/AndroidClient/androidchat/androidchat.iml b/src/AndroidClient/androidchat/androidchat.iml index fed055da..f801c812 100644 --- a/src/AndroidClient/androidchat/androidchat.iml +++ b/src/AndroidClient/androidchat/androidchat.iml @@ -104,7 +104,7 @@ - + @@ -124,6 +124,7 @@ + @@ -151,7 +152,6 @@ - diff --git a/src/AndroidClient/kotlin/kotlin.iml b/src/AndroidClient/kotlin/kotlin.iml index a23ff143..3cea186d 100644 --- a/src/AndroidClient/kotlin/kotlin.iml +++ b/src/AndroidClient/kotlin/kotlin.iml @@ -68,14 +68,6 @@ - - - - - - - - @@ -84,6 +76,14 @@ + + + + + + + + diff --git a/src/AndroidClient/techstacks/techstacks.iml b/src/AndroidClient/techstacks/techstacks.iml index cf633d6c..fd0d4bed 100644 --- a/src/AndroidClient/techstacks/techstacks.iml +++ b/src/AndroidClient/techstacks/techstacks.iml @@ -67,14 +67,6 @@ - - - - - - - - @@ -83,6 +75,14 @@ + + + + + + + + diff --git a/src/AndroidClient/techstackskotlin/techstackskotlin.iml b/src/AndroidClient/techstackskotlin/techstackskotlin.iml index b219c794..75bdef00 100644 --- a/src/AndroidClient/techstackskotlin/techstackskotlin.iml +++ b/src/AndroidClient/techstackskotlin/techstackskotlin.iml @@ -67,14 +67,6 @@ - - - - - - - - @@ -83,6 +75,14 @@ + + + + + + + + From d22ed1d2489badfbb14b7056eede2beea7c0c234 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 Mar 2017 23:36:07 -0500 Subject: [PATCH 006/211] Extract EventStream into external class so behavior can be overidden --- .../servicestack/client/sse/EventStream.java | 191 +++++++++++++++++ .../client/sse/ServerEventsClient.java | 197 ++---------------- .../servicestack/client/sse/EventStream.java | 191 +++++++++++++++++ .../client/sse/ServerEventsClient.java | 197 ++---------------- 4 files changed, 416 insertions(+), 360 deletions(-) create mode 100644 src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java create mode 100644 src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java new file mode 100644 index 00000000..2879f413 --- /dev/null +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java @@ -0,0 +1,191 @@ +package net.servicestack.client.sse; + +import net.servicestack.client.Log; +import net.servicestack.client.Utils; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +/** + * Created by mythz on 3/3/2017. + */ + +public class EventStream implements Runnable { + static int BufferSize = 1024 * 64; + + ServerEventsClient client; + ServerEventMessage currentMsg; + + public EventStream(ServerEventsClient client) { + this.client = client; + } + + protected InputStream getInputStream(URL streamUri) throws IOException { + HttpURLConnection req = (HttpURLConnection) streamUri.openConnection(); + return new BufferedInputStream(req.getInputStream()); + } + + public void close(){ + } + + @Override + public void run() { + try { + if (client.running.get()) + return; + client.running.set(true); + + URL streamUri = new URL(client.getEventStreamUri()); + InputStream is = getInputStream(streamUri); + client.errorsCount.set(0); + readStream(is); + } catch (InterruptedException ie){ + Log.i("EventStream.run(): Caught InterruptedException"); //thrown by interruptBackgroundThread() + return; + } catch (Exception e) { + Log.e("Error reading from event-stream, continuous errors: " + client.errorsCount.incrementAndGet(), e); + Log.e(Utils.getStackTrace(e)); + } finally { + client.running.set(false); + } + + if (!client.running.get()){ + client.restart(); + } + } + + protected int readFromStream(InputStream inputStream, byte[] buffer) throws IOException, InterruptedException { + int len; + while (true) { + int available = inputStream.available(); + if (available > 0) break; + Thread.sleep(1); + } + + len = inputStream.read(buffer); + return len; + } + + protected void readStream(InputStream inputStream) throws IOException, InterruptedException { + byte[] buffer = new byte[BufferSize]; + String overflowText = ""; + + int len = 0; + while (true) { + len = readFromStream(inputStream, buffer); + + if (len <= 0) + break; + + String text = overflowText + new String(buffer, 0, len, "UTF-8"); + + int pos; + while ((pos = text.indexOf('\n')) >= 0) { + if (pos == 0) { + if (currentMsg != null) + processEventMessage(currentMsg); + currentMsg = null; + + text = text.substring(pos + 1); + + if (!Utils.isEmpty(text)) + continue; + + break; + } + + String line = text.substring(0, pos); + if (!Utils.isNullOrWhiteSpace(line)) + processLine(line); + if (text.length() > pos + 1) + text = text.substring(pos + 1); + } + + overflowText = text; + } + + if (Log.isDebugEnabled()) + Log.d("Connection ended on " + client.getConnectionDisplayName()); + } + + protected void processLine(String line) { + if (line == null || line.length() == 0) + return; + + if (currentMsg == null) + currentMsg = new ServerEventMessage(); + + String[] parts = Utils.splitOnFirst(line, ':'); + String label = parts[0]; + String data = parts[1]; + if (data.length() > 0 && data.charAt(0) == ' ') + data = data.substring(1); + + if ("id".equals(label)) { + currentMsg.setEventId(Long.parseLong(data)); + } else if ("data".equals(label)) { + currentMsg.setData(data); + } + } + + protected void processEventMessage(ServerEventMessage e) { + String[] parts = Utils.splitOnFirst(e.getData(), ' '); + e.setSelector(parts[0]); + String[] selParts = Utils.splitOnFirst(e.getSelector(), '@'); + if (selParts.length > 1) { + e.setChannel(selParts[0]); + e.setSelector(selParts[1]); + } + + e.setJson(parts[1]); + + if (!Utils.isNullOrEmpty(e.getSelector())) { + parts = Utils.splitOnFirst(e.getSelector(), '.'); + if (parts.length < 2) + throw new IllegalArgumentException("Invalid Selector '" + e.getSelector() + "'"); + + e.setOp(parts[0]); + String target = parts[1].replace("%20", " "); + + String[] tokens = Utils.splitOnFirst(target, '$'); + e.setTarget(tokens[0]); + if (tokens.length > 1) + e.setCssSelector(tokens[1]); + + if ("cmd".equals(e.getOp())) { + target = e.getTarget(); + if ("onConnect".equals(target)) { + client.processOnConnectMessage(e); + return; + } else if ("onJoin".equals(target)) { + client.processOnJoinMessage(e); + return; + } else if ("onLeave".equals(target)) { + client.processOnLeaveMessage(e); + return; + } else if ("onUpdate".equals(target)) { + client.processOnUpdateMessage(e); + return; + } else if ("onHeartbeat".equals(target)) { + client.processOnHeartbeatMessage(e); + return; + } else { + ServerEventCallback cb = client.getHandlers().get(e.getTarget()); + if (cb != null) { + cb.execute(this.client, e); + } + } + } + + ServerEventCallback receiver = client.getNamedReceivers().get(e.getOp()); + if (receiver != null) { + receiver.execute(this.client, e); + } + } + + client.onMessageReceived(e); + } +} diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index c4295305..f5fc9903 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -11,12 +11,8 @@ import net.servicestack.func.Func; import net.servicestack.func.Function; -import java.io.BufferedInputStream; import java.io.Closeable; import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -63,10 +59,11 @@ public class ServerEventsClient implements Closeable { protected Date lastPulseAt; protected Thread bgThread; + protected EventStream bgEventStream; protected final AtomicBoolean stopped = new AtomicBoolean(false); protected final AtomicBoolean running = new AtomicBoolean(false); + protected final AtomicInteger errorsCount = new AtomicInteger(); - static int BufferSize = 1024 * 64; static int DefaultHeartbeatMs = 10 * 1000; static int DefaultIdleTimeoutMs = 30 * 1000; public static String UnknownChannel = "*"; @@ -275,8 +272,9 @@ public String getConnectionDisplayName() { : "(not connected)"; } - private synchronized void interruptBackgroundThread() { + protected synchronized void interruptBackgroundThread() { if (bgThread != null){ + bgEventStream.close(); bgThread.interrupt(); try { bgThread.join(); @@ -285,11 +283,16 @@ private synchronized void interruptBackgroundThread() { } } - public ServerEventsClient start(){ + protected EventStream createEventStream(){ + return new EventStream(this); + } + + public synchronized ServerEventsClient start(){ interruptBackgroundThread(); stopped.set(false); - bgThread = new Thread(new EventStream(this)); + bgEventStream = createEventStream(); + bgThread = new Thread(bgEventStream); bgThread.start(); lastPulseAt = new Date(); @@ -394,7 +397,7 @@ private void onHeartbeatReceived(ServerEventMessage e) { onHeartbeat.execute(e); } - private void onMessageReceived(ServerEventMessage e) { + protected void onMessageReceived(ServerEventMessage e) { if (Log.isDebugEnabled()) Log.d("[SSE-CLIENT] OnMessageReceived: " + e.getEventId() + " on #" + getConnectionDisplayName() + " " + Utils.join(channels, ",")); @@ -403,8 +406,6 @@ private void onMessageReceived(ServerEventMessage e) { onMessage.execute(e); } - private AtomicInteger errorsCount = new AtomicInteger(); - protected void onExceptionReceived(Exception ex) { errorsCount.incrementAndGet(); @@ -505,7 +506,7 @@ public void Heartbeat(){ } } - private void processOnConnectMessage(ServerEventMessage e) { + protected void processOnConnectMessage(ServerEventMessage e) { JsonObject msg = JsonUtils.toJsonObject(e.getJson()); connectionInfo = new ServerEventConnect(); @@ -522,19 +523,19 @@ private void processOnConnectMessage(ServerEventMessage e) { onConnectReceived(); } - private void processOnJoinMessage(ServerEventMessage e) { + protected void processOnJoinMessage(ServerEventMessage e) { onCommandReceived(new ServerEventJoin().populate(e, JsonUtils.toJsonObject(e.getJson()))); } - private void processOnLeaveMessage(ServerEventMessage e) { + protected void processOnLeaveMessage(ServerEventMessage e) { onCommandReceived(new ServerEventLeave().populate(e, JsonUtils.toJsonObject(e.getJson()))); } - private void processOnUpdateMessage(ServerEventMessage e) { + protected void processOnUpdateMessage(ServerEventMessage e) { onCommandReceived(new ServerEventUpdate().populate(e, JsonUtils.toJsonObject(e.getJson()))); } - private void processOnHeartbeatMessage(ServerEventMessage e) { + protected void processOnHeartbeatMessage(ServerEventMessage e) { lastPulseAt = new Date(); if (Log.isDebugEnabled()) Log.d("[SSE-CLIENT] LastPulseAt: " + new SimpleDateFormat("HH:mm:ss.SSS", Locale.US).format(lastPulseAt)); @@ -547,170 +548,6 @@ public void close() { stop(); } - class EventStream implements Runnable { - - ServerEventsClient client; - ServerEventMessage currentMsg; - - public EventStream(ServerEventsClient client) { - this.client = client; - } - - @Override - public void run() { - try { - if (running.get()) - return; - running.set(true); - - URL streamUri = new URL(client.getEventStreamUri()); - HttpURLConnection req = (HttpURLConnection) streamUri.openConnection(); - - InputStream is = new BufferedInputStream(req.getInputStream()); - errorsCount.set(0); - readStream(is); - } catch (InterruptedException ie){ - Log.i("EventStream.run(): Caught InterruptedException"); //thrown by interruptBackgroundThread() - return; - } catch (Exception e) { - Log.e("Error reading from event-stream, continuous errors: " + errorsCount.incrementAndGet(), e); - Log.e(Utils.getStackTrace(e)); - } finally { - running.set(false); - } - - if (!running.get()){ - client.restart(); - } - } - - private void readStream(InputStream inputStream) throws IOException, InterruptedException { - byte[] buffer = new byte[BufferSize]; - String overflowText = ""; - - int len = 0; - while (true) { - while (true) { - int available = inputStream.available(); - if (available > 0) break; - Thread.sleep(5); - } - - len = inputStream.read(buffer); - - if (len <= 0) - break; - - String text = overflowText + new String(buffer, 0, len, "UTF-8"); - - int pos; - while ((pos = text.indexOf('\n')) >= 0) { - if (pos == 0) { - if (currentMsg != null) - processEventMessage(currentMsg); - currentMsg = null; - - text = text.substring(pos + 1); - - if (!Utils.isEmpty(text)) - continue; - - break; - } - - String line = text.substring(0, pos); - if (!Utils.isNullOrWhiteSpace(line)) - processLine(line); - if (text.length() > pos + 1) - text = text.substring(pos + 1); - } - - overflowText = text; - } - - if (Log.isDebugEnabled()) - Log.d("Connection ended on " + client.getConnectionDisplayName()); - } - - private void processLine(String line) { - if (line == null || line.length() == 0) - return; - - if (currentMsg == null) - currentMsg = new ServerEventMessage(); - - String[] parts = Utils.splitOnFirst(line, ':'); - String label = parts[0]; - String data = parts[1]; - if (data.length() > 0 && data.charAt(0) == ' ') - data = data.substring(1); - - if ("id".equals(label)) { - currentMsg.setEventId(Long.parseLong(data)); - } else if ("data".equals(label)) { - currentMsg.setData(data); - } - } - - private void processEventMessage(ServerEventMessage e) { - String[] parts = Utils.splitOnFirst(e.getData(), ' '); - e.setSelector(parts[0]); - String[] selParts = Utils.splitOnFirst(e.getSelector(), '@'); - if (selParts.length > 1) { - e.setChannel(selParts[0]); - e.setSelector(selParts[1]); - } - - e.setJson(parts[1]); - - if (!Utils.isNullOrEmpty(e.getSelector())) { - parts = Utils.splitOnFirst(e.getSelector(), '.'); - if (parts.length < 2) - throw new IllegalArgumentException("Invalid Selector '" + e.getSelector() + "'"); - - e.setOp(parts[0]); - String target = parts[1].replace("%20", " "); - - String[] tokens = Utils.splitOnFirst(target, '$'); - e.setTarget(tokens[0]); - if (tokens.length > 1) - e.setCssSelector(tokens[1]); - - if ("cmd".equals(e.getOp())) { - target = e.getTarget(); - if ("onConnect".equals(target)) { - client.processOnConnectMessage(e); - return; - } else if ("onJoin".equals(target)) { - client.processOnJoinMessage(e); - return; - } else if ("onLeave".equals(target)) { - client.processOnLeaveMessage(e); - return; - } else if ("onUpdate".equals(target)) { - client.processOnUpdateMessage(e); - return; - } else if ("onHeartbeat".equals(target)) { - client.processOnHeartbeatMessage(e); - return; - } else { - ServerEventCallback cb = client.getHandlers().get(e.getTarget()); - if (cb != null) { - cb.execute(this.client, e); - } - } - } - - ServerEventCallback receiver = client.getNamedReceivers().get(e.getOp()); - if (receiver != null) { - receiver.execute(this.client, e); - } - } - - client.onMessageReceived(e); - } - } - public List getChannelSubscribers(){ ArrayList> response = this.serviceClient.get( new GetEventSubscribers().setChannels(Func.toList(this.getChannels()))); diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java new file mode 100644 index 00000000..2879f413 --- /dev/null +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java @@ -0,0 +1,191 @@ +package net.servicestack.client.sse; + +import net.servicestack.client.Log; +import net.servicestack.client.Utils; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +/** + * Created by mythz on 3/3/2017. + */ + +public class EventStream implements Runnable { + static int BufferSize = 1024 * 64; + + ServerEventsClient client; + ServerEventMessage currentMsg; + + public EventStream(ServerEventsClient client) { + this.client = client; + } + + protected InputStream getInputStream(URL streamUri) throws IOException { + HttpURLConnection req = (HttpURLConnection) streamUri.openConnection(); + return new BufferedInputStream(req.getInputStream()); + } + + public void close(){ + } + + @Override + public void run() { + try { + if (client.running.get()) + return; + client.running.set(true); + + URL streamUri = new URL(client.getEventStreamUri()); + InputStream is = getInputStream(streamUri); + client.errorsCount.set(0); + readStream(is); + } catch (InterruptedException ie){ + Log.i("EventStream.run(): Caught InterruptedException"); //thrown by interruptBackgroundThread() + return; + } catch (Exception e) { + Log.e("Error reading from event-stream, continuous errors: " + client.errorsCount.incrementAndGet(), e); + Log.e(Utils.getStackTrace(e)); + } finally { + client.running.set(false); + } + + if (!client.running.get()){ + client.restart(); + } + } + + protected int readFromStream(InputStream inputStream, byte[] buffer) throws IOException, InterruptedException { + int len; + while (true) { + int available = inputStream.available(); + if (available > 0) break; + Thread.sleep(1); + } + + len = inputStream.read(buffer); + return len; + } + + protected void readStream(InputStream inputStream) throws IOException, InterruptedException { + byte[] buffer = new byte[BufferSize]; + String overflowText = ""; + + int len = 0; + while (true) { + len = readFromStream(inputStream, buffer); + + if (len <= 0) + break; + + String text = overflowText + new String(buffer, 0, len, "UTF-8"); + + int pos; + while ((pos = text.indexOf('\n')) >= 0) { + if (pos == 0) { + if (currentMsg != null) + processEventMessage(currentMsg); + currentMsg = null; + + text = text.substring(pos + 1); + + if (!Utils.isEmpty(text)) + continue; + + break; + } + + String line = text.substring(0, pos); + if (!Utils.isNullOrWhiteSpace(line)) + processLine(line); + if (text.length() > pos + 1) + text = text.substring(pos + 1); + } + + overflowText = text; + } + + if (Log.isDebugEnabled()) + Log.d("Connection ended on " + client.getConnectionDisplayName()); + } + + protected void processLine(String line) { + if (line == null || line.length() == 0) + return; + + if (currentMsg == null) + currentMsg = new ServerEventMessage(); + + String[] parts = Utils.splitOnFirst(line, ':'); + String label = parts[0]; + String data = parts[1]; + if (data.length() > 0 && data.charAt(0) == ' ') + data = data.substring(1); + + if ("id".equals(label)) { + currentMsg.setEventId(Long.parseLong(data)); + } else if ("data".equals(label)) { + currentMsg.setData(data); + } + } + + protected void processEventMessage(ServerEventMessage e) { + String[] parts = Utils.splitOnFirst(e.getData(), ' '); + e.setSelector(parts[0]); + String[] selParts = Utils.splitOnFirst(e.getSelector(), '@'); + if (selParts.length > 1) { + e.setChannel(selParts[0]); + e.setSelector(selParts[1]); + } + + e.setJson(parts[1]); + + if (!Utils.isNullOrEmpty(e.getSelector())) { + parts = Utils.splitOnFirst(e.getSelector(), '.'); + if (parts.length < 2) + throw new IllegalArgumentException("Invalid Selector '" + e.getSelector() + "'"); + + e.setOp(parts[0]); + String target = parts[1].replace("%20", " "); + + String[] tokens = Utils.splitOnFirst(target, '$'); + e.setTarget(tokens[0]); + if (tokens.length > 1) + e.setCssSelector(tokens[1]); + + if ("cmd".equals(e.getOp())) { + target = e.getTarget(); + if ("onConnect".equals(target)) { + client.processOnConnectMessage(e); + return; + } else if ("onJoin".equals(target)) { + client.processOnJoinMessage(e); + return; + } else if ("onLeave".equals(target)) { + client.processOnLeaveMessage(e); + return; + } else if ("onUpdate".equals(target)) { + client.processOnUpdateMessage(e); + return; + } else if ("onHeartbeat".equals(target)) { + client.processOnHeartbeatMessage(e); + return; + } else { + ServerEventCallback cb = client.getHandlers().get(e.getTarget()); + if (cb != null) { + cb.execute(this.client, e); + } + } + } + + ServerEventCallback receiver = client.getNamedReceivers().get(e.getOp()); + if (receiver != null) { + receiver.execute(this.client, e); + } + } + + client.onMessageReceived(e); + } +} diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index c4295305..f5fc9903 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -11,12 +11,8 @@ import net.servicestack.func.Func; import net.servicestack.func.Function; -import java.io.BufferedInputStream; import java.io.Closeable; import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -63,10 +59,11 @@ public class ServerEventsClient implements Closeable { protected Date lastPulseAt; protected Thread bgThread; + protected EventStream bgEventStream; protected final AtomicBoolean stopped = new AtomicBoolean(false); protected final AtomicBoolean running = new AtomicBoolean(false); + protected final AtomicInteger errorsCount = new AtomicInteger(); - static int BufferSize = 1024 * 64; static int DefaultHeartbeatMs = 10 * 1000; static int DefaultIdleTimeoutMs = 30 * 1000; public static String UnknownChannel = "*"; @@ -275,8 +272,9 @@ public String getConnectionDisplayName() { : "(not connected)"; } - private synchronized void interruptBackgroundThread() { + protected synchronized void interruptBackgroundThread() { if (bgThread != null){ + bgEventStream.close(); bgThread.interrupt(); try { bgThread.join(); @@ -285,11 +283,16 @@ private synchronized void interruptBackgroundThread() { } } - public ServerEventsClient start(){ + protected EventStream createEventStream(){ + return new EventStream(this); + } + + public synchronized ServerEventsClient start(){ interruptBackgroundThread(); stopped.set(false); - bgThread = new Thread(new EventStream(this)); + bgEventStream = createEventStream(); + bgThread = new Thread(bgEventStream); bgThread.start(); lastPulseAt = new Date(); @@ -394,7 +397,7 @@ private void onHeartbeatReceived(ServerEventMessage e) { onHeartbeat.execute(e); } - private void onMessageReceived(ServerEventMessage e) { + protected void onMessageReceived(ServerEventMessage e) { if (Log.isDebugEnabled()) Log.d("[SSE-CLIENT] OnMessageReceived: " + e.getEventId() + " on #" + getConnectionDisplayName() + " " + Utils.join(channels, ",")); @@ -403,8 +406,6 @@ private void onMessageReceived(ServerEventMessage e) { onMessage.execute(e); } - private AtomicInteger errorsCount = new AtomicInteger(); - protected void onExceptionReceived(Exception ex) { errorsCount.incrementAndGet(); @@ -505,7 +506,7 @@ public void Heartbeat(){ } } - private void processOnConnectMessage(ServerEventMessage e) { + protected void processOnConnectMessage(ServerEventMessage e) { JsonObject msg = JsonUtils.toJsonObject(e.getJson()); connectionInfo = new ServerEventConnect(); @@ -522,19 +523,19 @@ private void processOnConnectMessage(ServerEventMessage e) { onConnectReceived(); } - private void processOnJoinMessage(ServerEventMessage e) { + protected void processOnJoinMessage(ServerEventMessage e) { onCommandReceived(new ServerEventJoin().populate(e, JsonUtils.toJsonObject(e.getJson()))); } - private void processOnLeaveMessage(ServerEventMessage e) { + protected void processOnLeaveMessage(ServerEventMessage e) { onCommandReceived(new ServerEventLeave().populate(e, JsonUtils.toJsonObject(e.getJson()))); } - private void processOnUpdateMessage(ServerEventMessage e) { + protected void processOnUpdateMessage(ServerEventMessage e) { onCommandReceived(new ServerEventUpdate().populate(e, JsonUtils.toJsonObject(e.getJson()))); } - private void processOnHeartbeatMessage(ServerEventMessage e) { + protected void processOnHeartbeatMessage(ServerEventMessage e) { lastPulseAt = new Date(); if (Log.isDebugEnabled()) Log.d("[SSE-CLIENT] LastPulseAt: " + new SimpleDateFormat("HH:mm:ss.SSS", Locale.US).format(lastPulseAt)); @@ -547,170 +548,6 @@ public void close() { stop(); } - class EventStream implements Runnable { - - ServerEventsClient client; - ServerEventMessage currentMsg; - - public EventStream(ServerEventsClient client) { - this.client = client; - } - - @Override - public void run() { - try { - if (running.get()) - return; - running.set(true); - - URL streamUri = new URL(client.getEventStreamUri()); - HttpURLConnection req = (HttpURLConnection) streamUri.openConnection(); - - InputStream is = new BufferedInputStream(req.getInputStream()); - errorsCount.set(0); - readStream(is); - } catch (InterruptedException ie){ - Log.i("EventStream.run(): Caught InterruptedException"); //thrown by interruptBackgroundThread() - return; - } catch (Exception e) { - Log.e("Error reading from event-stream, continuous errors: " + errorsCount.incrementAndGet(), e); - Log.e(Utils.getStackTrace(e)); - } finally { - running.set(false); - } - - if (!running.get()){ - client.restart(); - } - } - - private void readStream(InputStream inputStream) throws IOException, InterruptedException { - byte[] buffer = new byte[BufferSize]; - String overflowText = ""; - - int len = 0; - while (true) { - while (true) { - int available = inputStream.available(); - if (available > 0) break; - Thread.sleep(5); - } - - len = inputStream.read(buffer); - - if (len <= 0) - break; - - String text = overflowText + new String(buffer, 0, len, "UTF-8"); - - int pos; - while ((pos = text.indexOf('\n')) >= 0) { - if (pos == 0) { - if (currentMsg != null) - processEventMessage(currentMsg); - currentMsg = null; - - text = text.substring(pos + 1); - - if (!Utils.isEmpty(text)) - continue; - - break; - } - - String line = text.substring(0, pos); - if (!Utils.isNullOrWhiteSpace(line)) - processLine(line); - if (text.length() > pos + 1) - text = text.substring(pos + 1); - } - - overflowText = text; - } - - if (Log.isDebugEnabled()) - Log.d("Connection ended on " + client.getConnectionDisplayName()); - } - - private void processLine(String line) { - if (line == null || line.length() == 0) - return; - - if (currentMsg == null) - currentMsg = new ServerEventMessage(); - - String[] parts = Utils.splitOnFirst(line, ':'); - String label = parts[0]; - String data = parts[1]; - if (data.length() > 0 && data.charAt(0) == ' ') - data = data.substring(1); - - if ("id".equals(label)) { - currentMsg.setEventId(Long.parseLong(data)); - } else if ("data".equals(label)) { - currentMsg.setData(data); - } - } - - private void processEventMessage(ServerEventMessage e) { - String[] parts = Utils.splitOnFirst(e.getData(), ' '); - e.setSelector(parts[0]); - String[] selParts = Utils.splitOnFirst(e.getSelector(), '@'); - if (selParts.length > 1) { - e.setChannel(selParts[0]); - e.setSelector(selParts[1]); - } - - e.setJson(parts[1]); - - if (!Utils.isNullOrEmpty(e.getSelector())) { - parts = Utils.splitOnFirst(e.getSelector(), '.'); - if (parts.length < 2) - throw new IllegalArgumentException("Invalid Selector '" + e.getSelector() + "'"); - - e.setOp(parts[0]); - String target = parts[1].replace("%20", " "); - - String[] tokens = Utils.splitOnFirst(target, '$'); - e.setTarget(tokens[0]); - if (tokens.length > 1) - e.setCssSelector(tokens[1]); - - if ("cmd".equals(e.getOp())) { - target = e.getTarget(); - if ("onConnect".equals(target)) { - client.processOnConnectMessage(e); - return; - } else if ("onJoin".equals(target)) { - client.processOnJoinMessage(e); - return; - } else if ("onLeave".equals(target)) { - client.processOnLeaveMessage(e); - return; - } else if ("onUpdate".equals(target)) { - client.processOnUpdateMessage(e); - return; - } else if ("onHeartbeat".equals(target)) { - client.processOnHeartbeatMessage(e); - return; - } else { - ServerEventCallback cb = client.getHandlers().get(e.getTarget()); - if (cb != null) { - cb.execute(this.client, e); - } - } - } - - ServerEventCallback receiver = client.getNamedReceivers().get(e.getOp()); - if (receiver != null) { - receiver.execute(this.client, e); - } - } - - client.onMessageReceived(e); - } - } - public List getChannelSubscribers(){ ArrayList> response = this.serviceClient.get( new GetEventSubscribers().setChannels(Func.toList(this.getChannels()))); From f60c9b16df12a3680c75c2ee85ac529a03fdad5c Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 Mar 2017 23:36:55 -0500 Subject: [PATCH 007/211] refactor ServerEventTests to use shared factory method --- .../client/ServerEventClientTests.java | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java index 93a087ac..4186561d 100644 --- a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java +++ b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java @@ -34,10 +34,14 @@ public ServerEventClientTests() { Log.setInstance(new LogProvider("", true)); } + public ServerEventsClient createServerEventsClient(String baseUrl, String... channels){ + return new ServerEventsClient(baseUrl, channels); + } + public void test_Can_connect_to_ServerEventsStream() throws Exception { final CountDownLatch signal = new CountDownLatch(1); - try (ServerEventsClient client = new ServerEventsClient("http://chat.servicestack.net", "home") + try (ServerEventsClient client = createServerEventsClient("http://chat.servicestack.net", "home") .setOnConnect(e -> { System.out.print("onConnect: " + e); signal.countDown(); @@ -50,7 +54,7 @@ public void test_Can_connect_to_ServerEventsStream() throws Exception { public void test_Does_fire_onJoin_events() throws Exception { final CountDownLatch signal = new CountDownLatch(1); - try(ServerEventsClient client = new ServerEventsClient("http://chat.servicestack.net", "home")) + try(ServerEventsClient client = createServerEventsClient("http://chat.servicestack.net", "home")) { client .setOnConnect(e -> { @@ -75,7 +79,7 @@ public void test_Does_fire_onJoin_events_for_multiple_Channels() throws Exceptio String[] channels = new String[] { "A", "B", "C" }; List joinMsgs = new ArrayList<>(); - try (ServerEventsClient client = new ServerEventsClient("http://chat.servicestack.net", channels)) + try (ServerEventsClient client = createServerEventsClient("http://chat.servicestack.net", channels)) { client .setOnCommand(e -> { @@ -101,7 +105,7 @@ public void test_Does_fire_onJoin_events_for_multiple_Channels() throws Exceptio private void clearPreviousRun(String[] channels) throws Exception { final CountDownLatch signal = new CountDownLatch(1); - try (ServerEventsClient client = new ServerEventsClient("http://chat.servicestack.net", channels) + try (ServerEventsClient client = createServerEventsClient("http://chat.servicestack.net", channels) .setOnConnect(e -> { signal.countDown(); }) @@ -123,7 +127,7 @@ public void test_Does_fire_all_callbacks() throws Exception { List commands = new ArrayList<>(); List errors = new ArrayList<>(); - try(ServerEventsClient client1 = new ServerEventsClient("http://chat.servicestack.net") + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") .setOnConnect(connectMsgs::add) .setOnCommand(commands::add) .setOnMessage(msgs::add) @@ -146,7 +150,7 @@ public void test_Does_fire_all_callbacks() throws Exception { connectMsgs.clear(); commands.clear(); - try(ServerEventsClient client2 = new ServerEventsClient("http://chat.servicestack.net") + try(ServerEventsClient client2 = createServerEventsClient("http://chat.servicestack.net") .setOnConnect(connectMsgs::add) .start()) { @@ -226,12 +230,12 @@ public void test_Does_receive_messages() throws Exception { List msgs2 = new ArrayList<>(); try ( - ServerEventsClient client1 = new ServerEventsClient("http://chat.servicestack.net") + ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") .setOnConnect(connectMsgs::add) .setOnCommand(commands::add) .setOnMessage(msgs1::add); - ServerEventsClient client2 = new ServerEventsClient("http://chat.servicestack.net") + ServerEventsClient client2 = createServerEventsClient("http://chat.servicestack.net") .setOnConnect(connectMsgs::add) .setOnMessage(msgs2::add)) { @@ -304,7 +308,7 @@ public void test_Does_send_multiple_heartbeats() throws Exception { final CountDownLatch signal = new CountDownLatch(1); List heartbeats = new ArrayList<>(); - try(ServerEventsClient client1 = new ServerEventsClient("http://chat.servicestack.net") + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") .setOnConnect(e -> e.setHeartbeatIntervalMs(1000)) //change to 1s .setOnHeartbeat(e -> { heartbeats.add(e); @@ -323,7 +327,7 @@ public void test_Does_reconnect_on_lost_connection() throws Exception { List connectMsgs = new ArrayList<>(); List msgs1 = new ArrayList<>(); - try(ServerEventsClient client1 = new ServerEventsClient("http://chat.servicestack.net") + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") .setOnConnect(connectMsgs::add) .setOnMessage(msgs1::add) .start()) { @@ -340,7 +344,7 @@ public void test_Does_reconnect_on_lost_connection() throws Exception { client1.getServiceClient().post(new ResetServerEvents()); - try(ServerEventsClient client2 = new ServerEventsClient("http://chat.servicestack.net") + try(ServerEventsClient client2 = createServerEventsClient("http://chat.servicestack.net") .setOnConnect(connectMsgs::add) .start()) { @@ -367,7 +371,7 @@ public void test_Does_send_message_to_Handler() throws Exception { List chatMsgs = new ArrayList<>(); - try(ServerEventsClient client1 = new ServerEventsClient("http://chat.servicestack.net") + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") .registerHandler("chat", (client, e) -> { ChatMessage chatMsg = JsonUtils.fromJson(e.getJson(), ChatMessage.class); chatMsgs.add(chatMsg); @@ -398,7 +402,7 @@ public void test_Does_send_message_to_Handler() throws Exception { public void test_Does_send_message_to_named_receiver() throws Exception { List msgs1 = new ArrayList<>(); - try(ServerEventsClient client1 = new ServerEventsClient("http://chat.servicestack.net") + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") .registerNamedReceiver("test", TestNamedReceiver.class) .setOnMessage(msgs1::add) .start() @@ -462,7 +466,7 @@ public void test_Does_send_message_to_named_receiver() throws Exception { public void test_Does_send_message_to_global_receiver() throws Exception { List msgs1 = new ArrayList<>(); - try(ServerEventsClient client1 = new ServerEventsClient("http://chat.servicestack.net") + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") .registerReceiver(TestGlobalReceiver.class) .setOnMessage(msgs1::add) .start() @@ -486,7 +490,7 @@ public void test_Does_send_message_to_global_receiver() throws Exception { public void test_Does_set_properties_on_global_receiver() throws Exception { List msgs1 = new ArrayList<>(); - try(ServerEventsClient client1 = new ServerEventsClient("http://chat.servicestack.net") + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") .registerReceiver(TestGlobalReceiver.class) .setOnMessage(msgs1::add) .start() @@ -510,7 +514,7 @@ public void test_Does_set_properties_on_global_receiver() throws Exception { public void test_Does_send_raw_string_messages() throws Exception { List msgs1 = new ArrayList<>(); - try(ServerEventsClient client1 = new ServerEventsClient("http://chat.servicestack.net") + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") .registerReceiver(TestJavaScriptReceiver.class) .registerNamedReceiver("css", TestJavaScriptReceiver.class) .setOnMessage(msgs1::add) @@ -569,7 +573,7 @@ public void test_Does_send_raw_string_messages() throws Exception { public void test_Can_reuse_same_instance() throws Exception { List msgs1 = new ArrayList<>(); - try(ServerEventsClient client1 = new ServerEventsClient("http://chat.servicestack.net") + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") .registerReceiver(TestJavaScriptReceiver.class) .registerNamedReceiver("css", TestJavaScriptReceiver.class) .setResolver(new SingletonInstanceResolver()) @@ -607,16 +611,16 @@ public void test_Does_receive_messages_on_to_clients_subscribed_on_multiple_chan List msgsABC = new ArrayList<>(); List msgsABCD = new ArrayList<>(); - try(ServerEventsClient clientA = new ServerEventsClient("http://chat.servicestack.net", "A") + try(ServerEventsClient clientA = createServerEventsClient("http://chat.servicestack.net", "A") .setOnMessage(msgsA::add) .start(); - ServerEventsClient clientAB = new ServerEventsClient("http://chat.servicestack.net", "A", "B") + ServerEventsClient clientAB = createServerEventsClient("http://chat.servicestack.net", "A", "B") .setOnMessage(msgsAB::add) .start(); - ServerEventsClient clientABC = new ServerEventsClient("http://chat.servicestack.net", "A", "B", "C") + ServerEventsClient clientABC = createServerEventsClient("http://chat.servicestack.net", "A", "B", "C") .setOnMessage(msgsABC::add) .start(); - ServerEventsClient clientABCD = new ServerEventsClient("http://chat.servicestack.net", "A", "B", "C", "D") + ServerEventsClient clientABCD = createServerEventsClient("http://chat.servicestack.net", "A", "B", "C", "D") .setOnMessage(msgsABCD::add) .start()) { @@ -670,7 +674,7 @@ public void test_Does_receive_all_join_and_leave_messages() throws Exception { List leaveB = new ArrayList<>(); List leaveAB = new ArrayList<>(); - try(ServerEventsClient clientA = new ServerEventsClient("http://chat.servicestack.net", "A") + try(ServerEventsClient clientA = createServerEventsClient("http://chat.servicestack.net", "A") .setOnCommand(e -> { if (e instanceof ServerEventJoin){ joinA.add((ServerEventJoin)e); @@ -678,7 +682,7 @@ public void test_Does_receive_all_join_and_leave_messages() throws Exception { leaveA.add((ServerEventLeave)e); } }); - ServerEventsClient clientB = new ServerEventsClient("http://chat.servicestack.net", "B") + ServerEventsClient clientB = createServerEventsClient("http://chat.servicestack.net", "B") .setOnCommand(e -> { if (e instanceof ServerEventJoin){ joinB.add((ServerEventJoin)e); @@ -686,7 +690,7 @@ public void test_Does_receive_all_join_and_leave_messages() throws Exception { leaveB.add((ServerEventLeave)e); } }); - ServerEventsClient clientAB = new ServerEventsClient("http://chat.servicestack.net", "A", "B") + ServerEventsClient clientAB = createServerEventsClient("http://chat.servicestack.net", "A", "B") .setOnCommand(e -> { if (e instanceof ServerEventJoin){ joinAB.add((ServerEventJoin)e); @@ -753,7 +757,7 @@ public void test_MultiChannel_Does_receive_all_join_and_leave_messages() throws List leaveAB = new ArrayList<>(); try( - ServerEventsClient clientAB = new ServerEventsClient("http://chat.servicestack.net", "A", "B") + ServerEventsClient clientAB = createServerEventsClient("http://chat.servicestack.net", "A", "B") .setOnCommand(e -> { if (e instanceof ServerEventJoin){ joinAB.add((ServerEventJoin)e); @@ -761,7 +765,7 @@ public void test_MultiChannel_Does_receive_all_join_and_leave_messages() throws leaveAB.add((ServerEventLeave)e); } }); - ServerEventsClient clientA = new ServerEventsClient("http://chat.servicestack.net", "A") + ServerEventsClient clientA = createServerEventsClient("http://chat.servicestack.net", "A") .setOnCommand(e -> { if (e instanceof ServerEventJoin){ joinA.add((ServerEventJoin)e); @@ -769,7 +773,7 @@ public void test_MultiChannel_Does_receive_all_join_and_leave_messages() throws leaveA.add((ServerEventLeave)e); } }); - ServerEventsClient clientB = new ServerEventsClient("http://chat.servicestack.net", "B") + ServerEventsClient clientB = createServerEventsClient("http://chat.servicestack.net", "B") .setOnCommand(e -> { if (e instanceof ServerEventJoin){ joinB.add((ServerEventJoin)e); @@ -805,10 +809,10 @@ public void test_Can_subscribe_to_channels_whilst_connected() throws Exception { List msgs1 = new ArrayList<>(); List msgs2 = new ArrayList<>(); - try(ServerEventsClient client1 = new ServerEventsClient("http://chat.servicestack.net", "A") + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net", "A") .setOnMessage(msgs1::add) .start(); - ServerEventsClient client2 = new ServerEventsClient("http://chat.servicestack.net", "B") + ServerEventsClient client2 = createServerEventsClient("http://chat.servicestack.net", "B") .setOnMessage(msgs2::add) .start()) { @@ -857,11 +861,11 @@ public void test_Can_unsubscribe_from_channels_whilst_connected() throws Excepti List msgs1 = new ArrayList<>(); List msgs2 = new ArrayList<>(); - try(ServerEventsClient client1 = new ServerEventsClient("http://chat.servicestack.net", "A","B","C") + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net", "A","B","C") .setOnMessage(msgs1::add) .start() .waitTillConnected(); - ServerEventsClient client2 = new ServerEventsClient("http://chat.servicestack.net", "B","C") + ServerEventsClient client2 = createServerEventsClient("http://chat.servicestack.net", "B","C") .setOnMessage(msgs2::add) .start() .waitTillConnected()) { From f68b7855a0a06af2af1bada3667f1c919637b488 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 Mar 2017 23:40:33 -0500 Subject: [PATCH 008/211] remove unused deps from client/build.gradle/pom.xml --- src/AndroidClient/client/build.gradle | 6 ++---- src/AndroidClient/client/pom.xml | 14 +------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/AndroidClient/client/build.gradle b/src/AndroidClient/client/build.gradle index d772f76c..24c296d2 100644 --- a/src/AndroidClient/client/build.gradle +++ b/src/AndroidClient/client/build.gradle @@ -3,15 +3,13 @@ apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' +version = "1.0.28" dependencies { compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' - compile 'org.apache.httpcomponents:httpmime:4.2.3' - testCompile 'junit:junit:4.11' - testCompile 'org.mockito:mockito-core:1.9.5' + testCompile 'junit:junit:4.12' } -version = "1.0.28" group = "net.servicestack" // Maven Group ID for the artifact String packageId = "client" String groupID = group diff --git a/src/AndroidClient/client/pom.xml b/src/AndroidClient/client/pom.xml index 3d49fee1..230176a8 100644 --- a/src/AndroidClient/client/pom.xml +++ b/src/AndroidClient/client/pom.xml @@ -38,22 +38,10 @@ 2.8.0 compile - - org.apache.httpcomponents - httpmime - 4.2.3 - compile - junit junit - 4.11 - test - - - org.mockito - mockito-core - 1.9.5 + 4.12 test From 88077d8a160471e35803358ea0a34856822c7a31 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 Mar 2017 23:41:49 -0500 Subject: [PATCH 009/211] Update AndroidServerEventsClient to implement interruptible read using OkHttp --- .../android/AndroidServerEventsClient.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java index e14d5b73..f14e8b2b 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java @@ -5,6 +5,8 @@ import net.servicestack.client.AsyncResultVoid; import net.servicestack.client.AsyncSuccess; import net.servicestack.client.AsyncSuccessVoid; +import net.servicestack.client.Log; +import net.servicestack.client.sse.EventStream; import net.servicestack.client.sse.GetEventSubscribers; import net.servicestack.client.sse.ServerEventUser; import net.servicestack.client.sse.ServerEventsClient; @@ -12,10 +14,26 @@ import net.servicestack.client.sse.UpdateEventSubscriberResponse; import net.servicestack.func.Func; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.lang.reflect.Field; +import java.net.HttpURLConnection; +import java.net.SocketException; +import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.BufferedSource; + /** * Created by mythz on 2/15/2017. */ @@ -38,6 +56,73 @@ public AndroidServiceClient getAndroidClient(){ return (AndroidServiceClient) this.serviceClient; } + @Override + protected EventStream createEventStream() { + return new AndroidEventStream(this); + } + + public static final OkHttpClient client = new OkHttpClient(); + + class AndroidEventStream extends EventStream + { + public AndroidEventStream(ServerEventsClient client) { + super(client); + } + + Call call; + + @Override + protected InputStream getInputStream(URL streamUri) throws IOException { + + Request request = new Request.Builder() + .url(streamUri) + .build(); + + call = client.newCall(request); + Response response = call.execute(); + + return new BufferedInputStream(response.body().byteStream()); + } + + @Override + public void close() { + if (call == null) return; + call.cancel(); + } + + @Override + protected int readFromStream(InputStream inputStream, byte[] buffer) throws IOException, InterruptedException { + int len; + + //Simulates a bgThread.interrupt() so EventStream.run() exits gracefully + + try { + len = inputStream.read(buffer); + } catch (SocketException e){ + if (call.isCanceled()){ + throw new InterruptedException(); + } + throw e; + } + if (call.isCanceled()){ + throw new InterruptedException(); + } + return len; + } + } + + @Override + protected synchronized void interruptBackgroundThread() { + if (bgThread != null){ + bgEventStream.close(); + try { + bgThread.join(1000); + } catch (InterruptedException ignore) {} + bgThread = null; + bgEventStream = null; + } + } + public void getChannelSubscribersAsync(final AsyncResult> asyncResult){ this.getAndroidClient().getAsync( new GetEventSubscribers().setChannels(Func.toList(this.getChannels())), From e621a7c4fbb8dc229cd964097e97bedb1eaa6878 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 Mar 2017 23:42:26 -0500 Subject: [PATCH 010/211] Port ServerEventClientTests to android/Java 1.7 since trying to use Java 8 doesn't build --- .../src/androidTest/java/chat/chatdtos.java | 273 ++++ .../android/ServerEventClientTests.java | 1124 +++++++++++++++++ .../android/TestGlobalReceiver.java | 35 + .../android/TestJavaScriptReceiver.java | 45 + .../android/TestNamedReceiver.java | 40 + 5 files changed, 1517 insertions(+) create mode 100644 src/AndroidClient/android/src/androidTest/java/chat/chatdtos.java create mode 100644 src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java create mode 100644 src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestGlobalReceiver.java create mode 100644 src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestJavaScriptReceiver.java create mode 100644 src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestNamedReceiver.java diff --git a/src/AndroidClient/android/src/androidTest/java/chat/chatdtos.java b/src/AndroidClient/android/src/androidTest/java/chat/chatdtos.java new file mode 100644 index 00000000..1189595a --- /dev/null +++ b/src/AndroidClient/android/src/androidTest/java/chat/chatdtos.java @@ -0,0 +1,273 @@ +/* Options: +Date: 2017-02-12 03:54:05 +Version: 4.00 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: http://chat.servicestack.net + +Package: chat +GlobalNamespace: chatdtos +//AddPropertyAccessors: True +//SettersReturnThis: True +//AddServiceStackTypes: True +//AddResponseStatus: False +//AddDescriptionAsComments: True +//AddImplicitVersion: +//IncludeTypes: +ExcludeTypes: Authenticate,AuthenticateResponse,AssignRoles,AssignRolesResponse,UnAssignRoles,UnAssignRolesResponse +//TreatTypesAsStrings: +//DefaultImports: java.math.*,java.util.*,net.servicestack.client.*,com.google.gson.annotations.*,com.google.gson.reflect.* +*/ + +package chat; + +import java.math.*; +import java.util.*; +import net.servicestack.client.*; +import com.google.gson.annotations.*; +import com.google.gson.reflect.*; + +public class chatdtos +{ + + @Route("/channels/{Channel}/raw") + public static class PostRawToChannel implements IReturnVoid + { + public String from = null; + public String toUserId = null; + public String channel = null; + public String message = null; + public String selector = null; + + public String getFrom() { return from; } + public PostRawToChannel setFrom(String value) { this.from = value; return this; } + public String getToUserId() { return toUserId; } + public PostRawToChannel setToUserId(String value) { this.toUserId = value; return this; } + public String getChannel() { return channel; } + public PostRawToChannel setChannel(String value) { this.channel = value; return this; } + public String getMessage() { return message; } + public PostRawToChannel setMessage(String value) { this.message = value; return this; } + public String getSelector() { return selector; } + public PostRawToChannel setSelector(String value) { this.selector = value; return this; } + } + + @Route("/channels/{Channel}/chat") + public static class PostChatToChannel implements IReturn + { + public String from = null; + public String toUserId = null; + public String channel = null; + public String message = null; + public String selector = null; + + public String getFrom() { return from; } + public PostChatToChannel setFrom(String value) { this.from = value; return this; } + public String getToUserId() { return toUserId; } + public PostChatToChannel setToUserId(String value) { this.toUserId = value; return this; } + public String getChannel() { return channel; } + public PostChatToChannel setChannel(String value) { this.channel = value; return this; } + public String getMessage() { return message; } + public PostChatToChannel setMessage(String value) { this.message = value; return this; } + public String getSelector() { return selector; } + public PostChatToChannel setSelector(String value) { this.selector = value; return this; } + private static Object responseType = ChatMessage.class; + public Object getResponseType() { return responseType; } + } + + @Route("/chathistory") + public static class GetChatHistory implements IReturn + { + public ArrayList channels = null; + public Long afterId = null; + public Integer take = null; + + public ArrayList getChannels() { return channels; } + public GetChatHistory setChannels(ArrayList value) { this.channels = value; return this; } + public Long getAfterId() { return afterId; } + public GetChatHistory setAfterId(Long value) { this.afterId = value; return this; } + public Integer getTake() { return take; } + public GetChatHistory setTake(Integer value) { this.take = value; return this; } + private static Object responseType = GetChatHistoryResponse.class; + public Object getResponseType() { return responseType; } + } + + @Route("/reset") + public static class ClearChatHistory implements IReturnVoid + { + + } + + @Route("/reset-serverevents") + public static class ResetServerEvents implements IReturnVoid + { + + } + + @Route("/channels/{Channel}/object") + public static class PostObjectToChannel implements IReturnVoid + { + public String toUserId = null; + public String channel = null; + public String selector = null; + public CustomType customType = null; + public SetterType setterType = null; + + public String getToUserId() { return toUserId; } + public PostObjectToChannel setToUserId(String value) { this.toUserId = value; return this; } + public String getChannel() { return channel; } + public PostObjectToChannel setChannel(String value) { this.channel = value; return this; } + public String getSelector() { return selector; } + public PostObjectToChannel setSelector(String value) { this.selector = value; return this; } + public CustomType getCustomType() { return customType; } + public PostObjectToChannel setCustomType(CustomType value) { this.customType = value; return this; } + public SetterType getSetterType() { return setterType; } + public PostObjectToChannel setSetterType(SetterType value) { this.setterType = value; return this; } + } + + @Route("/account") + public static class GetUserDetails implements IReturn + { + + private static Object responseType = GetUserDetailsResponse.class; + public Object getResponseType() { return responseType; } + } + + public static class ChatMessage + { + public Long id = null; + public String channel = null; + public String fromUserId = null; + public String fromName = null; + public String displayName = null; + public String message = null; + public String userAuthId = null; + @SerializedName("private") public Boolean Private = null; + + public Long getId() { return id; } + public ChatMessage setId(Long value) { this.id = value; return this; } + public String getChannel() { return channel; } + public ChatMessage setChannel(String value) { this.channel = value; return this; } + public String getFromUserId() { return fromUserId; } + public ChatMessage setFromUserId(String value) { this.fromUserId = value; return this; } + public String getFromName() { return fromName; } + public ChatMessage setFromName(String value) { this.fromName = value; return this; } + public String getDisplayName() { return displayName; } + public ChatMessage setDisplayName(String value) { this.displayName = value; return this; } + public String getMessage() { return message; } + public ChatMessage setMessage(String value) { this.message = value; return this; } + public String getUserAuthId() { return userAuthId; } + public ChatMessage setUserAuthId(String value) { this.userAuthId = value; return this; } + public Boolean isPrivate() { return Private; } + public ChatMessage setPrivate(Boolean value) { this.Private = value; return this; } + } + + public static class GetChatHistoryResponse + { + public ArrayList results = null; + public ResponseStatus responseStatus = null; + + public ArrayList getResults() { return results; } + public GetChatHistoryResponse setResults(ArrayList value) { this.results = value; return this; } + public ResponseStatus getResponseStatus() { return responseStatus; } + public GetChatHistoryResponse setResponseStatus(ResponseStatus value) { this.responseStatus = value; return this; } + } + + public static class GetUserDetailsResponse + { + public String provider = null; + public String userId = null; + public String userName = null; + public String fullName = null; + public String displayName = null; + public String firstName = null; + public String lastName = null; + public String company = null; + public String email = null; + public String phoneNumber = null; + public Date birthDate = null; + public String birthDateRaw = null; + public String address = null; + public String address2 = null; + public String city = null; + public String state = null; + public String country = null; + public String culture = null; + public String gender = null; + public String language = null; + public String mailAddress = null; + public String nickname = null; + public String postalCode = null; + public String timeZone = null; + + public String getProvider() { return provider; } + public GetUserDetailsResponse setProvider(String value) { this.provider = value; return this; } + public String getUserId() { return userId; } + public GetUserDetailsResponse setUserId(String value) { this.userId = value; return this; } + public String getUserName() { return userName; } + public GetUserDetailsResponse setUserName(String value) { this.userName = value; return this; } + public String getFullName() { return fullName; } + public GetUserDetailsResponse setFullName(String value) { this.fullName = value; return this; } + public String getDisplayName() { return displayName; } + public GetUserDetailsResponse setDisplayName(String value) { this.displayName = value; return this; } + public String getFirstName() { return firstName; } + public GetUserDetailsResponse setFirstName(String value) { this.firstName = value; return this; } + public String getLastName() { return lastName; } + public GetUserDetailsResponse setLastName(String value) { this.lastName = value; return this; } + public String getCompany() { return company; } + public GetUserDetailsResponse setCompany(String value) { this.company = value; return this; } + public String getEmail() { return email; } + public GetUserDetailsResponse setEmail(String value) { this.email = value; return this; } + public String getPhoneNumber() { return phoneNumber; } + public GetUserDetailsResponse setPhoneNumber(String value) { this.phoneNumber = value; return this; } + public Date getBirthDate() { return birthDate; } + public GetUserDetailsResponse setBirthDate(Date value) { this.birthDate = value; return this; } + public String getBirthDateRaw() { return birthDateRaw; } + public GetUserDetailsResponse setBirthDateRaw(String value) { this.birthDateRaw = value; return this; } + public String getAddress() { return address; } + public GetUserDetailsResponse setAddress(String value) { this.address = value; return this; } + public String getAddress2() { return address2; } + public GetUserDetailsResponse setAddress2(String value) { this.address2 = value; return this; } + public String getCity() { return city; } + public GetUserDetailsResponse setCity(String value) { this.city = value; return this; } + public String getState() { return state; } + public GetUserDetailsResponse setState(String value) { this.state = value; return this; } + public String getCountry() { return country; } + public GetUserDetailsResponse setCountry(String value) { this.country = value; return this; } + public String getCulture() { return culture; } + public GetUserDetailsResponse setCulture(String value) { this.culture = value; return this; } + public String getGender() { return gender; } + public GetUserDetailsResponse setGender(String value) { this.gender = value; return this; } + public String getLanguage() { return language; } + public GetUserDetailsResponse setLanguage(String value) { this.language = value; return this; } + public String getMailAddress() { return mailAddress; } + public GetUserDetailsResponse setMailAddress(String value) { this.mailAddress = value; return this; } + public String getNickname() { return nickname; } + public GetUserDetailsResponse setNickname(String value) { this.nickname = value; return this; } + public String getPostalCode() { return postalCode; } + public GetUserDetailsResponse setPostalCode(String value) { this.postalCode = value; return this; } + public String getTimeZone() { return timeZone; } + public GetUserDetailsResponse setTimeZone(String value) { this.timeZone = value; return this; } + } + + public static class CustomType + { + public Integer id = null; + public String name = null; + + public Integer getId() { return id; } + public CustomType setId(Integer value) { this.id = value; return this; } + public String getName() { return name; } + public CustomType setName(String value) { this.name = value; return this; } + } + + public static class SetterType + { + public Integer id = null; + public String name = null; + + public Integer getId() { return id; } + public SetterType setId(Integer value) { this.id = value; return this; } + public String getName() { return name; } + public SetterType setName(String value) { this.name = value; return this; } + } + +} diff --git a/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java new file mode 100644 index 00000000..55910dd2 --- /dev/null +++ b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java @@ -0,0 +1,1124 @@ +package net.servicestack.android; + +import android.os.Build; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; +import static org.junit.Assert.assertArrayEquals; + +import net.servicestack.client.JsonUtils; +import net.servicestack.client.Log; +import net.servicestack.client.Utils; +import net.servicestack.client.sse.ExceptionCallback; +import net.servicestack.client.sse.GetEventSubscribers; +import net.servicestack.client.sse.ServerEventCallback; +import net.servicestack.client.sse.ServerEventConnect; +import net.servicestack.client.sse.ServerEventConnectCallback; +import net.servicestack.client.sse.ServerEventJoin; +import net.servicestack.client.sse.ServerEventLeave; +import net.servicestack.client.sse.ServerEventMessage; +import net.servicestack.client.sse.ServerEventMessageCallback; +import net.servicestack.client.sse.ServerEventUser; +import net.servicestack.client.sse.ServerEventsClient; +import net.servicestack.client.sse.SingletonInstanceResolver; +import net.servicestack.func.Func; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static chat.chatdtos.ChatMessage; +import static chat.chatdtos.CustomType; +import static chat.chatdtos.PostChatToChannel; +import static chat.chatdtos.PostObjectToChannel; +import static chat.chatdtos.PostRawToChannel; +import static chat.chatdtos.ResetServerEvents; +import static chat.chatdtos.SetterType; + +/** + * Created by mythz on 2/10/2017. + */ + +@android.support.annotation.RequiresApi(api = Build.VERSION_CODES.KITKAT) +@RunWith(AndroidJUnit4.class) +public class ServerEventClientTests { + + public ServerEventClientTests() { + Log.setInstance(new AndroidLogProvider("ZZZ", true)); + } + + public ServerEventsClient createServerEventsClient(String baseUrl, String... channels){ + return new AndroidServerEventsClient(baseUrl, channels); + } + + /* Project wont build if using Java 8 lambda's so replaced to use anon class */ + + @Test + public void Can_connect_to_ServerEventsStream() throws Exception { + final CountDownLatch signal = new CountDownLatch(1); + + try (ServerEventsClient client = createServerEventsClient("http://chat.servicestack.net", "home") + .setOnConnect(new ServerEventConnectCallback() { + @Override + public void execute(ServerEventConnect e) { + System.out.print("onConnect: " + e); + signal.countDown(); + } + }).start()) + { + assertTrue(signal.await(5, TimeUnit.SECONDS)); + } + } + + @Test + public void Does_fire_onJoin_events() throws Exception { + final CountDownLatch signal = new CountDownLatch(1); + + try(ServerEventsClient client = createServerEventsClient("http://chat.servicestack.net", "home")) + { + client + .setOnConnect(new ServerEventConnectCallback() { + @Override + public void execute(ServerEventConnect e) { + assertTrue(e.getHeartbeatUrl().startsWith("http://chat.servicestack.net")); + } + }) + .setOnCommand(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + System.out.print("onCommand: " + e); + assertTrue(e instanceof ServerEventJoin); + ServerEventJoin joinMsg = (ServerEventJoin) e; + assertEquals(client.getConnectionInfo().getDisplayName(), joinMsg.getDisplayName()); + signal.countDown(); + } + }) + .start(); + + assertTrue(signal.await(5, TimeUnit.SECONDS)); + } + } + + @Test + public void Does_fire_onJoin_events_for_multiple_Channels() throws Exception { + final CountDownLatch signal = new CountDownLatch(1); + + final String[] channels = new String[] { "A", "B", "C" }; + final List joinMsgs = new ArrayList<>(); + + try (ServerEventsClient client = createServerEventsClient("http://chat.servicestack.net", channels)) + { + client + .setOnCommand(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + System.out.print("onCommand: " + e); + + if (e instanceof ServerEventJoin) { + ServerEventJoin joinMsg = (ServerEventJoin) e; + joinMsgs.add(joinMsg); + + assertEquals(channels[joinMsgs.size() - 1], joinMsg.getChannel()); + assertEquals(client.getConnectionInfo().getDisplayName(), joinMsg.getDisplayName()); + + if (joinMsgs.size() == channels.length) + signal.countDown(); + } + } + }) + .start(); + + assertTrue(signal.await(5, TimeUnit.SECONDS)); + } + } + + private void clearPreviousRun(String[] channels) throws Exception { + final CountDownLatch signal = new CountDownLatch(1); + + try (ServerEventsClient client = createServerEventsClient("http://chat.servicestack.net", channels) + .setOnConnect(new ServerEventConnectCallback() { + @Override + public void execute(ServerEventConnect e) { + signal.countDown(); + } + }) + .start()) + { + assertTrue(signal.await(5, TimeUnit.SECONDS)); + } + } + +// @Test + public void ignore_test_ClearPreviousRun() throws Exception { + clearPreviousRun(null); + } + + @Test + public void Does_fire_all_callbacks() throws Exception { +// clearPreviousRun(null); + + final List connectMsgs = new ArrayList<>(); + final List msgs = new ArrayList<>(); + final List commands = new ArrayList<>(); + final List errors = new ArrayList<>(); + + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") + .setOnConnect(new ServerEventConnectCallback() { + @Override + public void execute(ServerEventConnect e) { + connectMsgs.add(e); + } + }) + .setOnCommand(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + commands.add(e); + } + }) + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgs.add(e); + } + }) + .setOnException(new ExceptionCallback() { + @Override + public void execute(Exception e) { + errors.add(e); + } + }) + .start()) + { + while (connectMsgs.size() < 1 || commands.size() < 1) { + Thread.sleep(100); + } + + ServerEventConnect connectMsg = Func.first(connectMsgs); + ServerEventJoin joinMsg = Func.first(Func.ofType(commands, ServerEventJoin.class)); + assertNotNull(connectMsg); + assertNotNull(joinMsg); + + assertEquals(0, msgs.size()); + assertEquals(0, errors.size()); + assertEquals(1, commands.size()); //join + + connectMsgs.clear(); + commands.clear(); + + try(ServerEventsClient client2 = createServerEventsClient("http://chat.servicestack.net") + .setOnConnect(new ServerEventConnectCallback() { + @Override + public void execute(ServerEventConnect e) { + connectMsgs.add(e); + } + }) + .start()) + { + while (connectMsgs.size() < 1 || commands.size() < 1) { + Thread.sleep(100); + } + + connectMsg = Func.first(connectMsgs); + joinMsg = Func.first(Func.ofType(commands, ServerEventJoin.class)); + + Utils.readToEnd(connectMsg.getUnRegisterUrl()); + } + + while (commands.size() < 2) { + Thread.sleep(100); + } + + ServerEventLeave leaveMsg = Func.first(Func.ofType(commands, ServerEventLeave.class)); + + assertNotNull(joinMsg); + assertNotNull(leaveMsg); + assertTrue(commands.size() >= 2); + assertEquals(errors.size(), 0); + } + } + + private void postChat(ServerEventsClient client, String message) { + postChat(client, message, null); + } + + private void postChat(ServerEventsClient client, String message, String channel) { + client.getServiceClient().post(new PostChatToChannel() + .setFrom(client.getSubscriptionId()) + .setMessage(message) + .setChannel(channel != null ? channel : ServerEventsClient.UnknownChannel) + .setSelector("cmd.chat")); + } + + private void postRaw(ServerEventsClient client, String selector, String message) { + postRaw(client, selector, message, null); + } + + private void postRaw(ServerEventsClient client, String selector, String message, String channel) { + client.getServiceClient().post(new PostRawToChannel() + .setFrom(client.getSubscriptionId()) + .setMessage(message) + .setChannel(channel != null ? channel : ServerEventsClient.UnknownChannel) + .setSelector(selector)); + } + + private void postObject(ServerEventsClient client, CustomType dto){ + postObject(client, dto, null, null); + } + + private void postObject(ServerEventsClient client, CustomType dto, String selector){ + postObject(client, dto, selector, null); + } + + private void postObject(ServerEventsClient client, CustomType dto, String selector, String channel){ + client.getServiceClient().post(new PostObjectToChannel() + .setCustomType(dto) + .setChannel(channel != null ? channel : ServerEventsClient.UnknownChannel) + .setSelector(selector)); + } + + private void postObject(ServerEventsClient client, SetterType dto){ + client.getServiceClient().post(new PostObjectToChannel() + .setSetterType(dto) + .setChannel(ServerEventsClient.UnknownChannel)); + } + + @Test + public void Does_receive_messages() throws Exception { + + final List connectMsgs = new ArrayList<>(); + final List commands = new ArrayList<>(); + final List msgs1 = new ArrayList<>(); + final List msgs2 = new ArrayList<>(); + + try ( + ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") + .setOnConnect(new ServerEventConnectCallback() { + @Override + public void execute(ServerEventConnect e) { + connectMsgs.add(e); + } + }) + .setOnCommand(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + commands.add(e); + } + }) + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgs1.add(e); + } + }); + + ServerEventsClient client2 = createServerEventsClient("http://chat.servicestack.net") + .setOnConnect(new ServerEventConnectCallback() { + @Override + public void execute(ServerEventConnect e) { + connectMsgs.add(e); + } + }) + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgs2.add(e); + } + })) + { + client1.start(); + + while (connectMsgs.size() < 1 || commands.size() < 1) { + Thread.sleep(100); + } + + client2.start(); + + while (connectMsgs.size() < 2 || commands.size() < 2) { + Thread.sleep(100); + } + + ServerEventConnect info1 = connectMsgs.get(0); + postChat(client1, "hello from client1"); + + while (msgs1.size() < 1 || msgs2.size() < 1) { + Thread.sleep(100); + } + + ServerEventMessage msg1 = Func.first(msgs1); + ServerEventMessage msg2 = Func.first(msgs2); + + assertTrue(msg1.getEventId() > 0); + assertTrue(msg2.getEventId() > 0); + assertEquals("cmd.chat", msg1.getSelector()); + assertEquals("cmd.chat", msg2.getSelector()); + + ChatMessage chatMsg1 = JsonUtils.fromJson(msg1.getJson(), ChatMessage.class); + ChatMessage chatMsg2 = JsonUtils.fromJson(msg2.getJson(), ChatMessage.class); + + for (ChatMessage chatMsg : new ChatMessage[]{ chatMsg1, chatMsg2 }){ + assertTrue(chatMsg.getId() > 0); + assertEquals(info1.getUserId(), chatMsg.getFromUserId()); + assertEquals(info1.getDisplayName(), chatMsg.getFromName()); + assertEquals(info1.getDisplayName(), chatMsg.getFromName()); + } + + assertEquals(1, msgs1.size()); + assertEquals(1, msgs2.size()); + + ServerEventConnect info2 = connectMsgs.get(1); + postChat(client2, "hello from client2"); + + while (msgs1.size() < 2 || msgs2.size() < 2) { + Thread.sleep(100); + } + + msg1 = msgs1.get(1); + msg2 = msgs2.get(1); + + chatMsg1 = JsonUtils.fromJson(msg1.getJson(), ChatMessage.class); + chatMsg2 = JsonUtils.fromJson(msg2.getJson(), ChatMessage.class); + + for (ChatMessage chatMsg : new ChatMessage[]{ chatMsg1, chatMsg2 }){ + assertTrue(chatMsg.getId() > 0); + assertEquals(info2.getUserId(), chatMsg.getFromUserId()); + assertEquals(info2.getDisplayName(), chatMsg.getFromName()); + assertEquals(info2.getDisplayName(), chatMsg.getFromName()); + } + + assertEquals(2, msgs1.size()); + assertEquals(2, msgs2.size()); + } + } + + @Test + public void Does_send_multiple_heartbeats() throws Exception { + final CountDownLatch signal = new CountDownLatch(1); + + final List heartbeats = new ArrayList<>(); + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") + .setOnConnect(new ServerEventConnectCallback() { + @Override + public void execute(ServerEventConnect e) { + e.setHeartbeatIntervalMs(1000); + } + }) //change to 1s + .setOnHeartbeat(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + heartbeats.add(e); + if (heartbeats.size() >= 3) + signal.countDown(); + } + }) + .start()) { + + assertTrue(signal.await(5, TimeUnit.SECONDS)); + + assertTrue(heartbeats.size() >= 3); + } + } + + @Test + public void Does_reconnect_on_lost_connection() throws Exception { + + final List connectMsgs = new ArrayList<>(); + final List msgs1 = new ArrayList<>(); + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") + .setOnConnect(new ServerEventConnectCallback() { + @Override + public void execute(ServerEventConnect e) { + connectMsgs.add(e); + } + }) + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgs1.add(e); + } + }) + .start()) { + + while (connectMsgs.size() < 1){ + Thread.sleep(100); + } + + postChat(client1, "msg1 from client1"); + + while (msgs1.size() < 1){ + Thread.sleep(100); + } + + client1.getServiceClient().post(new ResetServerEvents()); + + try(ServerEventsClient client2 = createServerEventsClient("http://chat.servicestack.net") + .setOnConnect(new ServerEventConnectCallback() { + @Override + public void execute(ServerEventConnect e) { + connectMsgs.add(e); + } + }) + .start()) { + + while (connectMsgs.size() < 3){ //client1 + client1 reconnect + client2 + Thread.sleep(100); + } + + postChat(client2, "msg2 from client2"); + + while (msgs1.size() < 2){ //msg1 + msg2 + Thread.sleep(100); + } + } + + ServerEventMessage msg2 = msgs1.get(1); + + ChatMessage chatMsg2 = JsonUtils.fromJson(msg2.getJson(), ChatMessage.class); + + assertEquals("msg2 from client2", chatMsg2.getMessage()); + } + } + + @Test + public void Does_send_message_to_Handler() throws Exception { + + final List chatMsgs = new ArrayList<>(); + + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") + .registerHandler("chat", new ServerEventCallback() { + @Override + public void execute(ServerEventsClient client, ServerEventMessage e) { + ChatMessage chatMsg = JsonUtils.fromJson(e.getJson(), ChatMessage.class); + chatMsgs.add(chatMsg); + } + }) + .start() + .waitTillConnected()) { + + postChat(client1, "msg1"); + + while (chatMsgs.size() < 1){ + Thread.sleep(100); + } + + ChatMessage chatMsg = Func.last(chatMsgs); + assertEquals("msg1", chatMsg.getMessage()); + + postChat(client1, "msg2"); + + while (chatMsgs.size() < 2){ + Thread.sleep(100); + } + + chatMsg = Func.last(chatMsgs); + assertEquals("msg2", chatMsg.getMessage()); + } + } + + @Test + public void Does_send_message_to_named_receiver() throws Exception { + final List msgs1 = new ArrayList<>(); + + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") + .registerNamedReceiver("test", TestNamedReceiver.class) + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgs1.add(e); + } + }) + .start() + .waitTillConnected()) { + + postObject(client1, new CustomType() + .setId(1) + .setName("Foo"), "test.FooMethod"); + + while (msgs1.size() < 1){ + Thread.sleep(100); + } + + CustomType foo = TestNamedReceiver.FooMethodReceived; + assertNotNull(foo); + assertEquals(1, foo.getId().intValue()); + assertEquals("Foo", foo.getName()); + + postObject(client1, new CustomType() + .setId(2) + .setName("Bar"), "test.BarMethod"); + + while (msgs1.size() < 2){ + Thread.sleep(100); + } + + CustomType bar = TestNamedReceiver.BarMethodReceived; + assertNotNull(bar); + assertEquals(2, bar.getId().intValue()); + assertEquals("Bar", bar.getName()); + + postObject(client1, new CustomType() + .setId(3) + .setName("Baz"), "test.BazMethod"); + + while (msgs1.size() < 3){ + Thread.sleep(100); + } + + CustomType baz = TestNamedReceiver.NoSuchMethodReceived; + assertNotNull(baz); + assertEquals(3, baz.getId().intValue()); + assertEquals("Baz", baz.getName()); + assertEquals("BazMethod", TestNamedReceiver.NoSuchMethodSelector); + + postObject(client1, new CustomType() + .setId(4) + .setName("Qux"), "test.QuxSetter"); + + while (msgs1.size() < 4){ + Thread.sleep(100); + } + + CustomType qux = TestNamedReceiver.QuxSetterReceived; + assertNotNull(qux); + assertEquals(4, qux.getId().intValue()); + assertEquals("Qux", qux.getName()); + } + } + + @Test + public void Does_send_message_to_global_receiver() throws Exception { + final List msgs1 = new ArrayList<>(); + + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") + .registerReceiver(TestGlobalReceiver.class) + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgs1.add(e); + } + }) + .start() + .waitTillConnected()) { + + postObject(client1, new CustomType() + .setId(1) + .setName("Foo")); + + while (msgs1.size() < 1){ + Thread.sleep(100); + } + + CustomType foo = TestGlobalReceiver.FooMethodReceived; + assertNotNull(foo); + assertEquals(1, foo.getId().intValue()); + assertEquals("Foo", foo.getName()); + } + } + + @Test + public void Does_set_properties_on_global_receiver() throws Exception { + final List msgs1 = new ArrayList<>(); + + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") + .registerReceiver(TestGlobalReceiver.class) + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgs1.add(e); + } + }) + .start() + .waitTillConnected()) { + + postObject(client1, new SetterType() + .setId(1) + .setName("Foo")); + + while (msgs1.size() < 1){ + Thread.sleep(100); + } + + SetterType foo = TestGlobalReceiver.AnyNamedSetterReceived; + assertNotNull(foo); + assertEquals(1, foo.getId().intValue()); + assertEquals("Foo", foo.getName()); + } + } + + @Test + public void Does_send_raw_string_messages() throws Exception { + final List msgs1 = new ArrayList<>(); + + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") + .registerReceiver(TestJavaScriptReceiver.class) + .registerNamedReceiver("css", TestJavaScriptReceiver.class) + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgs1.add(e); + } + }) + .start() + .waitTillConnected()) { + + postChat(client1, "chat msg"); + + while (msgs1.size() < 1) { + Thread.sleep(100); + } + + ChatMessage chatMsg = TestJavaScriptReceiver.ChatReceived; + assertNotNull(chatMsg); + assertEquals("chat msg", chatMsg.getMessage()); + + postRaw(client1, "cmd.announce", "This is your captain speaking..."); + + while (msgs1.size() < 2) { + Thread.sleep(100); + } + + String announce = TestJavaScriptReceiver.AnnounceReceived; + assertEquals("This is your captain speaking...", announce); + + postRaw(client1, "cmd.toggle$#channels", null); + + while (msgs1.size() < 3) { + Thread.sleep(100); + } + + String toggle = TestJavaScriptReceiver.ToggleReceived; + assertEquals("", toggle); + ServerEventMessage toggleRequest = TestJavaScriptReceiver.ToggleRequestReceived; + assertEquals("cmd.toggle$#channels", toggleRequest.getSelector()); + assertEquals("cmd", toggleRequest.getOp()); + assertEquals("toggle", toggleRequest.getTarget()); + assertEquals("#channels", toggleRequest.getCssSelector()); + + postRaw(client1, "css.background-image$#top", "url(http://bit.ly/1yIJOBH)"); + + while (msgs1.size() < 4) { + Thread.sleep(100); + } + + String bgImage = TestJavaScriptReceiver.BackgroundImageReceived; + assertEquals("url(http://bit.ly/1yIJOBH)", bgImage); + ServerEventMessage bgImageRequest = TestJavaScriptReceiver.BackgroundImageRequestReceived; + assertEquals("css.background-image$#top", bgImageRequest.getSelector()); + assertEquals("css", bgImageRequest.getOp()); + assertEquals("background-image", bgImageRequest.getTarget()); + assertEquals("#top", bgImageRequest.getCssSelector()); + } + } + + @Test + public void Can_reuse_same_instance() throws Exception { + final List msgs1 = new ArrayList<>(); + + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") + .registerReceiver(TestJavaScriptReceiver.class) + .registerNamedReceiver("css", TestJavaScriptReceiver.class) + .setResolver(new SingletonInstanceResolver()) + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgs1.add(e); + } + }) + .start() + .waitTillConnected()) { + + postRaw(client1, "cmd.announce", "This is your captain speaking..."); + + while (msgs1.size() < 1) { + Thread.sleep(100); + } + + TestJavaScriptReceiver instance = (TestJavaScriptReceiver)client1.getResolver().TryResolve(TestJavaScriptReceiver.class); + assertEquals("This is your captain speaking...", instance.AnnounceInstance); + + postRaw(client1, "cmd.announce", "2nd Announcement"); + + while (msgs1.size() < 2) { + Thread.sleep(100); + } + + assertEquals("2nd Announcement", instance.AnnounceInstance); + } + } + + public void Can_use_IOC_to_autowire_Receivers(){ + //No built-in IOC + } + + @Test + public void Does_receive_messages_on_to_clients_subscribed_on_multiple_channels() throws Exception { + + final List msgsA = new ArrayList<>(); + final List msgsAB = new ArrayList<>(); + final List msgsABC = new ArrayList<>(); + final List msgsABCD = new ArrayList<>(); + + try(ServerEventsClient clientA = createServerEventsClient("http://chat.servicestack.net", "A") + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgsA.add(e); + } + }) + .start(); + ServerEventsClient clientAB = createServerEventsClient("http://chat.servicestack.net", "A", "B") + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgsAB.add(e); + } + }) + .start(); + ServerEventsClient clientABC = createServerEventsClient("http://chat.servicestack.net", "A", "B", "C") + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgsABC.add(e); + } + }) + .start(); + ServerEventsClient clientABCD = createServerEventsClient("http://chat.servicestack.net", "A", "B", "C", "D") + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgsABCD.add(e); + } + }) + .start()) { + + clientA.waitTillConnected(); + clientAB.waitTillConnected(); + clientABC.waitTillConnected(); + clientABCD.waitTillConnected(); + + List channelAsubscribers = clientA.getChannelSubscribers(); + assertEquals(4, channelAsubscribers.size()); + + List channelABsubscribers = clientAB.getChannelSubscribers(); + assertEquals(4, channelABsubscribers.size()); + + System.out.println("Publishing Msg Batch #1 ..."); + postChat(clientA, "#1 hello to A", "A"); + postChat(clientA, "#2 hello to B", "B"); + postChat(clientA, "#3 hello to C", "C"); + postChat(clientA, "#4 hello to D", "D"); + + Thread.sleep(1000); + + assertEquals(1, msgsA.size()); + assertEquals(2, msgsAB.size()); + assertEquals(3, msgsABC.size()); + assertEquals(4, msgsABCD.size()); + + Thread.sleep(1000); + + System.out.println("Publishing Msg Batch #2 ..."); + postChat(clientA, "#5 hello to A", "A"); + postChat(clientA, "#6 hello to B", "B"); + postChat(clientA, "#7 hello to C", "C"); + postChat(clientA, "#8 hello to D", "D"); + + Thread.sleep(1000); + + assertEquals(2, msgsA.size()); + assertEquals(4, msgsAB.size()); + assertEquals(6, msgsABC.size()); + assertEquals(8, msgsABCD.size()); + } + } + + @Test + public void Does_receive_all_join_and_leave_messages() throws Exception { + final List joinA = new ArrayList<>(); + final List joinB = new ArrayList<>(); + final List joinAB = new ArrayList<>(); + + final List leaveA = new ArrayList<>(); + final List leaveB = new ArrayList<>(); + final List leaveAB = new ArrayList<>(); + + try(ServerEventsClient clientA = createServerEventsClient("http://chat.servicestack.net", "A") + .setOnCommand(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + if (e instanceof ServerEventJoin) { + joinA.add((ServerEventJoin) e); + } else if (e instanceof ServerEventLeave) { + leaveA.add((ServerEventLeave) e); + } + } + }); + ServerEventsClient clientB = createServerEventsClient("http://chat.servicestack.net", "B") + .setOnCommand(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + if (e instanceof ServerEventJoin) { + joinB.add((ServerEventJoin) e); + } else if (e instanceof ServerEventLeave) { + leaveB.add((ServerEventLeave) e); + } + } + }); + ServerEventsClient clientAB = createServerEventsClient("http://chat.servicestack.net", "A", "B") + .setOnCommand(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + if (e instanceof ServerEventJoin) { + joinAB.add((ServerEventJoin) e); + } else if (e instanceof ServerEventLeave) { + leaveAB.add((ServerEventLeave) e); + } + } + }); + ){ + + clientA.start().waitTillConnected(); + clientB.start().waitTillConnected(); + clientAB.start().waitTillConnected(); + + while (joinA.size() < 2 || joinB.size() < 2 || joinAB.size() < 2){ + Thread.sleep(100); + } + + assertEquals(2, joinA.size()); //A + [(A) B] + assertEquals(2, joinB.size()); //B + [A (B)] + assertEquals(2, joinAB.size()); //[(A) B] + [A (B)] + + List channelAsubscribers = clientA.getChannelSubscribers(); + assertEquals(2, channelAsubscribers.size()); + + List channelBsubscribers = clientB.getChannelSubscribers(); + assertEquals(2, channelBsubscribers.size()); + + List channelABsubscribers = clientAB.getChannelSubscribers(); + assertEquals(3, channelABsubscribers.size()); + + ArrayList> usersA = clientA.getServiceClient().get(new GetEventSubscribers() + .setChannels(Func.toList("A"))); + ArrayList> usersB = clientA.getServiceClient().get(new GetEventSubscribers() + .setChannels(Func.toList("B"))); + ArrayList> usersAB = clientA.getServiceClient().get(new GetEventSubscribers() + .setChannels(Func.toList("A", "B"))); + + assertEquals(2, usersA.size()); + assertEquals(2, usersB.size()); + assertEquals(3, usersAB.size()); + + clientAB.stop(); + + Thread.sleep(100); + + clientB.stop(); + clientA.stop(); + + Thread.sleep(100); + + assertEquals(1, leaveA.size()); + assertEquals(1, leaveB.size()); + assertEquals(0, leaveAB.size()); + } + } + + @Test + public void MultiChannel_Does_receive_all_join_and_leave_messages() throws Exception { + final List joinA = new ArrayList<>(); + final List joinB = new ArrayList<>(); + final List joinAB = new ArrayList<>(); + + final List leaveA = new ArrayList<>(); + final List leaveB = new ArrayList<>(); + final List leaveAB = new ArrayList<>(); + + try(ServerEventsClient clientAB = createServerEventsClient("http://chat.servicestack.net", "A", "B") + .setOnCommand(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + if (e instanceof ServerEventJoin) { + joinAB.add((ServerEventJoin) e); + } else if (e instanceof ServerEventLeave) { + leaveAB.add((ServerEventLeave) e); + } + } + }); + ServerEventsClient clientA = createServerEventsClient("http://chat.servicestack.net", "A") + .setOnCommand(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + if (e instanceof ServerEventJoin) { + joinA.add((ServerEventJoin) e); + } else if (e instanceof ServerEventLeave) { + leaveA.add((ServerEventLeave) e); + } + } + }); + ServerEventsClient clientB = createServerEventsClient("http://chat.servicestack.net", "B") + .setOnCommand(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + if (e instanceof ServerEventJoin) { + joinB.add((ServerEventJoin) e); + } else if (e instanceof ServerEventLeave) { + leaveB.add((ServerEventLeave) e); + } + } + }); + ){ + + clientAB.start().waitTillConnected(); + clientA.start().waitTillConnected(); + clientB.start().waitTillConnected(); + + while (joinAB.size() < 4 //[(A) B] + [A (B)] + A + B + || joinA.size() < 1 || joinB.size() < 1) { + Thread.sleep(100); + } + + clientA.stop(); + clientB.stop(); + + Thread.sleep(100); + + clientAB.stop(); + + assertEquals(2, leaveAB.size()); + assertEquals(0, leaveA.size()); + assertEquals(0, leaveB.size()); + } + } + + @Test + public void Can_subscribe_to_channels_whilst_connected() throws Exception { + final List msgs1 = new ArrayList<>(); + final List msgs2 = new ArrayList<>(); + + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net", "A") + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgs1.add(e); + } + }) + .start(); + ServerEventsClient client2 = createServerEventsClient("http://chat.servicestack.net", "B") + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgs2.add(e); + } + }) + .start()) { + + client1.waitTillConnected(); + client2.waitTillConnected(); + + assertArrayEquals(new String[]{"A"}, client1.getChannels()); + + postChat(client2, "#1 hello to B", "B"); + + Thread.sleep(500); + + assertEquals(0, msgs1.size()); + assertEquals(1, msgs2.size()); + + client1.subscribeToChannels("B"); + + Thread.sleep(500); + + postChat(client2, "#2 hello to B", "B"); + postChat(client2, "#3 hello to C", "C"); + Thread.sleep(500); + + assertArrayEquals(new String[]{"A", "B"}, client1.getChannels()); + assertArrayEquals(new String[]{"B"}, client2.getChannels()); + + assertTrue(client1.getEventStreamUri().endsWith("?channels=A,B")); + assertTrue(client2.getEventStreamUri().endsWith("?channels=B")); + + client1.subscribeToChannels("C"); + client2.subscribeToChannels("C"); + Thread.sleep(500); + + postChat(client2, "#4 hello to C", "C"); + Thread.sleep(500); + + assertArrayEquals(new String[]{"A", "B", "C"}, client1.getChannels()); + assertArrayEquals(new String[]{"B", "C"}, client2.getChannels()); + + assertTrue(client1.getEventStreamUri().endsWith("?channels=A,B,C")); + assertTrue(client2.getEventStreamUri().endsWith("?channels=B,C")); + } + } + + @Test + public void Can_unsubscribe_from_channels_whilst_connected() throws Exception { + final List msgs1 = new ArrayList<>(); + final List msgs2 = new ArrayList<>(); + + try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net", "A","B","C") + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgs1.add(e); + } + }) + .start() + .waitTillConnected(); + ServerEventsClient client2 = createServerEventsClient("http://chat.servicestack.net", "B","C") + .setOnMessage(new ServerEventMessageCallback() { + @Override + public void execute(ServerEventMessage e) { + msgs2.add(e); + } + }) + .start() + .waitTillConnected()) { + + assertArrayEquals(new String[]{"A","B","C"}, client1.getChannels()); + + postChat(client2, "#1 hello to B", "B"); + Thread.sleep(500); + + assertEquals(1, msgs1.size()); + assertEquals(1, msgs2.size()); + + client1.unSubscribeFromChannels("B"); + Thread.sleep(500); + + postChat(client2, "#2 hello to B", "B"); + postChat(client2, "#3 hello to C", "C"); + Thread.sleep(500); + + assertEquals(2, msgs1.size()); + assertEquals(3, msgs2.size()); + + assertArrayEquals(new String[]{"A", "C"}, client1.getChannels()); + assertArrayEquals(new String[]{"B", "C"}, client2.getChannels()); + + assertTrue(client1.getEventStreamUri().endsWith("?channels=A,C")); + assertTrue(client2.getEventStreamUri().endsWith("?channels=B,C")); + + client1.unSubscribeFromChannels("C"); + client2.unSubscribeFromChannels("C"); + Thread.sleep(500); + + postChat(client2, "#4 hello to C", "C"); + Thread.sleep(500); + + assertArrayEquals(new String[]{"A"}, client1.getChannels()); + assertArrayEquals(new String[]{"B"}, client2.getChannels()); + + assertTrue(client1.getEventStreamUri().endsWith("?channels=A")); + assertTrue(client2.getEventStreamUri().endsWith("?channels=B")); + } + } +} diff --git a/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestGlobalReceiver.java b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestGlobalReceiver.java new file mode 100644 index 00000000..319c80c4 --- /dev/null +++ b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestGlobalReceiver.java @@ -0,0 +1,35 @@ +package net.servicestack.android; + +import net.servicestack.client.JsonUtils; +import net.servicestack.client.sse.ServerEventMessage; +import net.servicestack.client.sse.ServerEventReceiver; + +import static chat.chatdtos.*; + +/** + * Created by mythz on 2/12/2017. + */ + +public class TestGlobalReceiver extends ServerEventReceiver { + public static CustomType FooMethodReceived; + public static CustomType NoSuchMethodReceived; + public static String NoSuchMethodSelector; + public static SetterType AnyNamedSetterReceived; + + public void setAnyNamedSetter(SetterType value) { + AnyNamedSetterReceived = value; + } + + public void anyNamedMethod(CustomType request) + { + FooMethodReceived = request; + } + + @Override + public void noSuchMethod(String selector, Object message) + { + ServerEventMessage msg = (ServerEventMessage)message; + NoSuchMethodReceived = JsonUtils.fromJson(msg.getJson(), CustomType.class); + NoSuchMethodSelector = selector; + } +} diff --git a/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestJavaScriptReceiver.java b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestJavaScriptReceiver.java new file mode 100644 index 00000000..643f7ceb --- /dev/null +++ b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestJavaScriptReceiver.java @@ -0,0 +1,45 @@ +package net.servicestack.android; + +import net.servicestack.client.sse.ServerEventMessage; +import net.servicestack.client.sse.ServerEventReceiver; + +import chat.chatdtos; + +import static chat.chatdtos.*; + +/** + * Created by mythz on 2/12/2017. + */ + +public class TestJavaScriptReceiver extends ServerEventReceiver { + public static ChatMessage ChatReceived; + public static String AnnounceReceived; + public String AnnounceInstance; + public static String ToggleReceived; + public static ServerEventMessage ToggleRequestReceived; + public static String BackgroundImageReceived; + public static ServerEventMessage BackgroundImageRequestReceived; + + public void chat(ChatMessage message) + { + ChatReceived = message; + } + + public void announce(String message) + { + AnnounceReceived = message; + AnnounceInstance = message; + } + + public void toggle(String message) + { + ToggleReceived = message; + ToggleRequestReceived = super.getRequest(); + } + + public void backgroundImage(String cssRule) + { + BackgroundImageReceived = cssRule; + BackgroundImageRequestReceived = super.getRequest(); + } +} diff --git a/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestNamedReceiver.java b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestNamedReceiver.java new file mode 100644 index 00000000..984cf1c0 --- /dev/null +++ b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestNamedReceiver.java @@ -0,0 +1,40 @@ +package net.servicestack.android; + +import net.servicestack.client.JsonUtils; +import net.servicestack.client.sse.ServerEventMessage; +import net.servicestack.client.sse.ServerEventReceiver; + +import static chat.chatdtos.*; + +/** + * Created by mythz on 2/11/2017. + */ + +public class TestNamedReceiver extends ServerEventReceiver { + + public static CustomType FooMethodReceived; + public static CustomType BarMethodReceived; + public static CustomType NoSuchMethodReceived; + public static String NoSuchMethodSelector; + public static CustomType QuxSetterReceived; + + public void setQuxSetter(CustomType value){ + QuxSetterReceived = value; + } + + public void fooMethod(CustomType request) { + FooMethodReceived = request; + } + + public CustomType barMethod(CustomType request) { + BarMethodReceived = request; + return request; + } + + @Override + public void noSuchMethod(String selector, Object message) { + ServerEventMessage msg = (ServerEventMessage)message; + NoSuchMethodReceived = JsonUtils.fromJson(msg.getJson(), CustomType.class); + NoSuchMethodSelector = selector; + } +} From f88eaee3bf03e02b59139fdf667cf6da1b7ebfee Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 Mar 2017 23:43:06 -0500 Subject: [PATCH 011/211] Update android build.gradle --- src/AndroidClient/android/build.gradle | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/AndroidClient/android/build.gradle b/src/AndroidClient/android/build.gradle index b21c000f..a5dc706a 100644 --- a/src/AndroidClient/android/build.gradle +++ b/src/AndroidClient/android/build.gradle @@ -1,19 +1,30 @@ apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' version = "1.0.28" +dependencies { + compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' + compile 'com.squareup.okhttp3:okhttp:3.6.0' + compile fileTree(include: '*.jar', dir: 'libs') + androidTestCompile 'junit:junit:4.12' + androidTestCompile 'com.android.support.test:runner:0.5' + androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2' + androidTestCompile 'com.android.support:support-annotations:25.2.0' +} + android { - compileSdkVersion 24 - buildToolsVersion "23.0.2" + compileSdkVersion 25 + buildToolsVersion "25.0.2" defaultConfig { minSdkVersion 15 - targetSdkVersion 24 + targetSdkVersion 25 versionCode 1 versionName version + + testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' } buildTypes { release { @@ -94,13 +105,6 @@ install { } } -dependencies { - compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' - compile fileTree(include: '*.jar', dir: 'libs') - testCompile 'junit:junit:4.11' - testCompile 'org.mockito:mockito-core:1.9.5' - compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" -} repositories { mavenCentral() } From f8e892b813bc49603037cded80ca9a4c297578fc Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 Mar 2017 23:43:21 -0500 Subject: [PATCH 012/211] Upgrade androidchat/build.gradle --- src/AndroidClient/androidchat/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AndroidClient/androidchat/build.gradle b/src/AndroidClient/androidchat/build.gradle index 1bc4d3f9..c7762f50 100644 --- a/src/AndroidClient/androidchat/build.gradle +++ b/src/AndroidClient/androidchat/build.gradle @@ -53,8 +53,8 @@ dependencies { exclude group: 'com.android.support', module: 'support-annotations' }) compile project(':android') - compile 'com.android.support:appcompat-v7:25.1.1' - compile 'com.android.support:design:25.1.1' + compile 'com.android.support:appcompat-v7:25.2.0' + compile 'com.android.support:design:25.2.0' compile 'net.servicestack:android:1.0.27' compile 'com.facebook.android:facebook-android-sdk:[4,5)' compile('com.twitter.sdk.android:twitter:2.3.1@aar') { From 519be290dcf512e545d11a00a528090cc9648c77 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 Mar 2017 23:43:31 -0500 Subject: [PATCH 013/211] Update proj files --- src/AndroidClient/android/android.iml | 31 ++++++--- src/AndroidClient/androidchat/androidchat.iml | 64 +++++++++---------- src/AndroidClient/app/app.iml | 41 ++++++++---- src/AndroidClient/client/client.iml | 6 +- src/AndroidClient/kotlin/kotlin.iml | 26 +++++++- src/AndroidClient/techstacks/techstacks.iml | 27 ++++++-- .../techstackskotlin/techstackskotlin.iml | 22 ++++++- 7 files changed, 147 insertions(+), 70 deletions(-) diff --git a/src/AndroidClient/android/android.iml b/src/AndroidClient/android/android.iml index 2341381c..2e94d658 100644 --- a/src/AndroidClient/android/android.iml +++ b/src/AndroidClient/android/android.iml @@ -89,6 +89,11 @@ + + + + + @@ -104,15 +109,25 @@ - + - - - + + + + - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AndroidClient/androidchat/androidchat.iml b/src/AndroidClient/androidchat/androidchat.iml index f801c812..584b5cbf 100644 --- a/src/AndroidClient/androidchat/androidchat.iml +++ b/src/AndroidClient/androidchat/androidchat.iml @@ -85,25 +85,27 @@ + + - - + + - - - - - - - - - - + + + + + + + + + + @@ -111,8 +113,8 @@ + - @@ -121,27 +123,27 @@ + - - - + + - + - - + + @@ -152,28 +154,24 @@ - + + + - + - - + - + - - - - + + + + - - - - - \ No newline at end of file diff --git a/src/AndroidClient/app/app.iml b/src/AndroidClient/app/app.iml index b85563bd..b591e10f 100644 --- a/src/AndroidClient/app/app.iml +++ b/src/AndroidClient/app/app.iml @@ -67,14 +67,6 @@ - - - - - - - - @@ -83,15 +75,28 @@ + + + + + + + + + + + + + @@ -102,10 +107,22 @@ - - + + + + - - + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AndroidClient/client/client.iml b/src/AndroidClient/client/client.iml index 6edafde7..73d50594 100644 --- a/src/AndroidClient/client/client.iml +++ b/src/AndroidClient/client/client.iml @@ -28,11 +28,7 @@ - - - - + - \ No newline at end of file diff --git a/src/AndroidClient/kotlin/kotlin.iml b/src/AndroidClient/kotlin/kotlin.iml index 3cea186d..6ed3a096 100644 --- a/src/AndroidClient/kotlin/kotlin.iml +++ b/src/AndroidClient/kotlin/kotlin.iml @@ -84,8 +84,11 @@ + + + @@ -96,13 +99,19 @@ + + + + + + @@ -122,9 +131,20 @@ - + + + + - - + + + + + + + + + + \ No newline at end of file diff --git a/src/AndroidClient/techstacks/techstacks.iml b/src/AndroidClient/techstacks/techstacks.iml index fd0d4bed..b78bb195 100644 --- a/src/AndroidClient/techstacks/techstacks.iml +++ b/src/AndroidClient/techstacks/techstacks.iml @@ -84,6 +84,8 @@ + + @@ -94,11 +96,14 @@ + + + @@ -115,12 +120,22 @@ - - - + + + + - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AndroidClient/techstackskotlin/techstackskotlin.iml b/src/AndroidClient/techstackskotlin/techstackskotlin.iml index 75bdef00..34e205d7 100644 --- a/src/AndroidClient/techstackskotlin/techstackskotlin.iml +++ b/src/AndroidClient/techstackskotlin/techstackskotlin.iml @@ -84,6 +84,8 @@ + + @@ -96,11 +98,14 @@ + + + @@ -123,9 +128,20 @@ - + + + + - - + + + + + + + + + + \ No newline at end of file From f552ba1fdd3e75db07eb1003bb4f4996d8459a61 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 Mar 2017 00:02:48 -0500 Subject: [PATCH 014/211] Add lint.xml to disable false positive build error --- src/AndroidClient/android/lint.xml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/AndroidClient/android/lint.xml diff --git a/src/AndroidClient/android/lint.xml b/src/AndroidClient/android/lint.xml new file mode 100644 index 00000000..3c6f61fb --- /dev/null +++ b/src/AndroidClient/android/lint.xml @@ -0,0 +1,7 @@ + + + + + + + From e2c9363bb2a06fea86852ca74007d26762d3ee49 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 Mar 2017 00:10:48 -0500 Subject: [PATCH 015/211] bump to v1.0.29 --- src/AndroidClient/android/build.gradle | 2 +- src/AndroidClient/client/build.gradle | 2 +- src/AndroidClient/client/pom.xml | 2 +- src/AndroidClient/kotlin/kotlin.iml | 16 ++++++++-------- .../techstackskotlin/techstackskotlin.iml | 16 ++++++++-------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/AndroidClient/android/build.gradle b/src/AndroidClient/android/build.gradle index a5dc706a..f6844453 100644 --- a/src/AndroidClient/android/build.gradle +++ b/src/AndroidClient/android/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.library' apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' -version = "1.0.28" +version = "1.0.29" dependencies { compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/src/AndroidClient/client/build.gradle b/src/AndroidClient/client/build.gradle index 24c296d2..6c904552 100644 --- a/src/AndroidClient/client/build.gradle +++ b/src/AndroidClient/client/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' -version = "1.0.28" +version = "1.0.29" dependencies { compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/src/AndroidClient/client/pom.xml b/src/AndroidClient/client/pom.xml index 230176a8..fa4d04e6 100644 --- a/src/AndroidClient/client/pom.xml +++ b/src/AndroidClient/client/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.servicestack client - 1.0.28 + 1.0.29 ServiceStack.Client A client library to call your ServiceStack webservices. https://github.com/ServiceStack/ServiceStack.Java diff --git a/src/AndroidClient/kotlin/kotlin.iml b/src/AndroidClient/kotlin/kotlin.iml index 6ed3a096..2e721932 100644 --- a/src/AndroidClient/kotlin/kotlin.iml +++ b/src/AndroidClient/kotlin/kotlin.iml @@ -68,14 +68,6 @@ - - - - - - - - @@ -84,6 +76,14 @@ + + + + + + + + diff --git a/src/AndroidClient/techstackskotlin/techstackskotlin.iml b/src/AndroidClient/techstackskotlin/techstackskotlin.iml index 34e205d7..e5421280 100644 --- a/src/AndroidClient/techstackskotlin/techstackskotlin.iml +++ b/src/AndroidClient/techstackskotlin/techstackskotlin.iml @@ -67,14 +67,6 @@ - - - - - - - - @@ -83,6 +75,14 @@ + + + + + + + + From db63d1a810ef8fa102cc5c5a445ea76089b4383f Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 Mar 2017 02:53:05 -0500 Subject: [PATCH 016/211] Share cookies between built-in HttpURLConnection and OkHttpClient --- .../android/AndroidServerEventsClient.java | 18 ++- .../android/JavaNetCookieJar.java | 119 ++++++++++++++++++ 2 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 src/AndroidClient/android/src/main/java/net/servicestack/android/JavaNetCookieJar.java diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java index f14e8b2b..841ff976 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java @@ -19,6 +19,7 @@ import java.io.InputStream; import java.io.InterruptedIOException; import java.lang.reflect.Field; +import java.net.CookieHandler; import java.net.HttpURLConnection; import java.net.SocketException; import java.net.URL; @@ -39,9 +40,15 @@ */ public class AndroidServerEventsClient extends ServerEventsClient { + protected OkHttpClient client; + public AndroidServerEventsClient(String baseUri, String... channels) { super(baseUri, channels); this.serviceClient = new AndroidServiceClient(this.baseUri); + + client = new OkHttpClient.Builder() + .cookieJar(new JavaNetCookieJar(CookieHandler.getDefault())) + .build(); } public AndroidServerEventsClient(String baseUrl, String channel) { @@ -52,6 +59,15 @@ public AndroidServerEventsClient(String baseUrl) { this(baseUrl, new String[]{}); } + public AndroidServerEventsClient setOkHttpClient(OkHttpClient client){ + this.client = client; + return this; + } + + public OkHttpClient getOkHttpClient(){ + return client; + } + public AndroidServiceClient getAndroidClient(){ return (AndroidServiceClient) this.serviceClient; } @@ -61,8 +77,6 @@ protected EventStream createEventStream() { return new AndroidEventStream(this); } - public static final OkHttpClient client = new OkHttpClient(); - class AndroidEventStream extends EventStream { public AndroidEventStream(ServerEventsClient client) { diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/android/JavaNetCookieJar.java b/src/AndroidClient/android/src/main/java/net/servicestack/android/JavaNetCookieJar.java new file mode 100644 index 00000000..d8479094 --- /dev/null +++ b/src/AndroidClient/android/src/main/java/net/servicestack/android/JavaNetCookieJar.java @@ -0,0 +1,119 @@ +package net.servicestack.android; +/* + * Copyright (C) 2015 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.IOException; +import java.net.CookieHandler; +import java.net.HttpCookie; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import okhttp3.Cookie; +import okhttp3.CookieJar; +import okhttp3.HttpUrl; +import okhttp3.internal.platform.Platform; + +import static okhttp3.internal.Util.delimiterOffset; +import static okhttp3.internal.Util.trimSubstring; +import static okhttp3.internal.platform.Platform.WARN; + +/** A cookie jar that delegates to a {@link java.net.CookieHandler}. */ +public final class JavaNetCookieJar implements CookieJar { + + private final CookieHandler cookieHandler; + + public JavaNetCookieJar(CookieHandler cookieHandler) { + this.cookieHandler = cookieHandler; + } + + @Override + public void saveFromResponse(HttpUrl url, List cookies) { + if (cookieHandler != null) { + List cookieStrings = new ArrayList<>(); + for (Cookie cookie : cookies) { + cookieStrings.add(cookie.toString()); + } + Map> multimap = Collections.singletonMap("Set-Cookie", cookieStrings); + try { + cookieHandler.put(url.uri(), multimap); + } catch (IOException e) { + Platform.get().log(WARN, "Saving cookies failed for " + url.resolve("/..."), e); + } + } + } + + @Override + public List loadForRequest(HttpUrl url) { + // The RI passes all headers. We don't have 'em, so we don't pass 'em! + Map> headers = Collections.emptyMap(); + Map> cookieHeaders; + try { + cookieHeaders = cookieHandler.get(url.uri(), headers); + } catch (IOException e) { + Platform.get().log(WARN, "Loading cookies failed for " + url.resolve("/..."), e); + return Collections.emptyList(); + } + + List cookies = null; + for (Map.Entry> entry : cookieHeaders.entrySet()) { + String key = entry.getKey(); + if (("Cookie".equalsIgnoreCase(key) || "Cookie2".equalsIgnoreCase(key)) + && !entry.getValue().isEmpty()) { + for (String header : entry.getValue()) { + if (cookies == null) cookies = new ArrayList<>(); + cookies.addAll(decodeHeaderAsJavaNetCookies(url, header)); + } + } + } + + return cookies != null + ? Collections.unmodifiableList(cookies) + : Collections.emptyList(); + } + + /** + * Convert a request header to OkHttp's cookies via {@link HttpCookie}. That extra step handles + * multiple cookies in a single request header, which {@link Cookie#parse} doesn't support. + */ + private List decodeHeaderAsJavaNetCookies(HttpUrl url, String header) { + List result = new ArrayList<>(); + for (int pos = 0, limit = header.length(), pairEnd; pos < limit; pos = pairEnd + 1) { + pairEnd = delimiterOffset(header, pos, limit, ";,"); + int equalsSign = delimiterOffset(header, pos, pairEnd, '='); + String name = trimSubstring(header, pos, equalsSign); + if (name.startsWith("$")) continue; + + // We have either name=value or just a name. + String value = equalsSign < pairEnd + ? trimSubstring(header, equalsSign + 1, pairEnd) + : ""; + + // If the value is "quoted", drop the quotes. + if (value.startsWith("\"") && value.endsWith("\"")) { + value = value.substring(1, value.length() - 1); + } + + result.add(new Cookie.Builder() + .name(name) + .value(value) + .domain(url.host()) + .build()); + } + return result; + } +} From fe46c28f0e7a441db2a242cd87e104b3d3d37c32 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 Mar 2017 21:56:45 -0500 Subject: [PATCH 017/211] comments + tweaks --- .../java/net/servicestack/client/sse/EventStream.java | 6 ++++-- .../net/servicestack/client/sse/ServerEventsClient.java | 8 ++++---- .../java/net/servicestack/client/sse/EventStream.java | 6 ++++-- .../net/servicestack/client/sse/ServerEventsClient.java | 8 ++++---- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java index 2879f413..9a914d06 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java @@ -43,7 +43,8 @@ public void run() { client.errorsCount.set(0); readStream(is); } catch (InterruptedException ie){ - Log.i("EventStream.run(): Caught InterruptedException"); //thrown by interruptBackgroundThread() + //Caused by stopBackgroundThread(), exit without restarting as the new bgThread does it + Log.i("EventStream.run(): Caught InterruptedException"); return; } catch (Exception e) { Log.e("Error reading from event-stream, continuous errors: " + client.errorsCount.incrementAndGet(), e); @@ -60,9 +61,10 @@ public void run() { protected int readFromStream(InputStream inputStream, byte[] buffer) throws IOException, InterruptedException { int len; while (true) { + //Checking if bytes are available to read to avoid performing a blocking read int available = inputStream.available(); if (available > 0) break; - Thread.sleep(1); + Thread.sleep(1); //If bgThread was interrupted this throws an InterruptedException } len = inputStream.read(buffer); diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index f5fc9903..58244d27 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -272,10 +272,10 @@ public String getConnectionDisplayName() { : "(not connected)"; } - protected synchronized void interruptBackgroundThread() { + protected synchronized void stopBackgroundThread() { if (bgThread != null){ bgEventStream.close(); - bgThread.interrupt(); + bgThread.interrupt(); //notify the bgThread to exit try { bgThread.join(); } catch (InterruptedException ignore) {} @@ -288,7 +288,7 @@ protected EventStream createEventStream(){ } public synchronized ServerEventsClient start(){ - interruptBackgroundThread(); + stopBackgroundThread(); stopped.set(false); bgEventStream = createEventStream(); @@ -370,7 +370,7 @@ private synchronized void internalStop() { } connectionInfo = null; - interruptBackgroundThread(); + stopBackgroundThread(); } private void onCommandReceived(ServerEventMessage e) { diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java index 2879f413..9a914d06 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java @@ -43,7 +43,8 @@ public void run() { client.errorsCount.set(0); readStream(is); } catch (InterruptedException ie){ - Log.i("EventStream.run(): Caught InterruptedException"); //thrown by interruptBackgroundThread() + //Caused by stopBackgroundThread(), exit without restarting as the new bgThread does it + Log.i("EventStream.run(): Caught InterruptedException"); return; } catch (Exception e) { Log.e("Error reading from event-stream, continuous errors: " + client.errorsCount.incrementAndGet(), e); @@ -60,9 +61,10 @@ public void run() { protected int readFromStream(InputStream inputStream, byte[] buffer) throws IOException, InterruptedException { int len; while (true) { + //Checking if bytes are available to read to avoid performing a blocking read int available = inputStream.available(); if (available > 0) break; - Thread.sleep(1); + Thread.sleep(1); //If bgThread was interrupted this throws an InterruptedException } len = inputStream.read(buffer); diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index f5fc9903..58244d27 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -272,10 +272,10 @@ public String getConnectionDisplayName() { : "(not connected)"; } - protected synchronized void interruptBackgroundThread() { + protected synchronized void stopBackgroundThread() { if (bgThread != null){ bgEventStream.close(); - bgThread.interrupt(); + bgThread.interrupt(); //notify the bgThread to exit try { bgThread.join(); } catch (InterruptedException ignore) {} @@ -288,7 +288,7 @@ protected EventStream createEventStream(){ } public synchronized ServerEventsClient start(){ - interruptBackgroundThread(); + stopBackgroundThread(); stopped.set(false); bgEventStream = createEventStream(); @@ -370,7 +370,7 @@ private synchronized void internalStop() { } connectionInfo = null; - interruptBackgroundThread(); + stopBackgroundThread(); } private void onCommandReceived(ServerEventMessage e) { From bc6280a52b01e6f1ededdae5b372cae9555111e8 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 Mar 2017 21:57:36 -0500 Subject: [PATCH 018/211] AndroidServerEventsClient fixes --- .../android/AndroidServerEventsClient.java | 13 +++++----- src/AndroidClient/androidchat/androidchat.iml | 1 + .../net/androidchat/Extensions.java | 24 +++++++++---------- .../net/androidchat/MainActivity.java | 18 +++++++------- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java index 841ff976..dbb3b7ef 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java @@ -113,6 +113,7 @@ protected int readFromStream(InputStream inputStream, byte[] buffer) throws IOEx try { len = inputStream.read(buffer); } catch (SocketException e){ + //if we caused the Exception with call.cancel() treat as bgThread.interrupt() if (call.isCanceled()){ throw new InterruptedException(); } @@ -126,11 +127,11 @@ protected int readFromStream(InputStream inputStream, byte[] buffer) throws IOEx } @Override - protected synchronized void interruptBackgroundThread() { + protected synchronized void stopBackgroundThread() { if (bgThread != null){ bgEventStream.close(); try { - bgThread.join(1000); + bgThread.join(100); } catch (InterruptedException ignore) {} bgThread = null; bgEventStream = null; @@ -218,11 +219,11 @@ public void complete() { }); } - public void subscribeToChannelsAsync(final String[] channels, final AsyncSuccess success){ + public void subscribeToChannelsAsync(final String[] channels, final AsyncSuccessVoid success){ subscribeToChannelsAsync(channels, AsyncUtils.createAsyncResult(success, null)); } - public void subscribeToChannelsAsync(final String[] channels, final AsyncSuccess success, final AsyncError error){ + public void subscribeToChannelsAsync(final String[] channels, final AsyncSuccessVoid success, final AsyncError error){ subscribeToChannelsAsync(channels, AsyncUtils.createAsyncResult(success, error)); } @@ -248,11 +249,11 @@ public void complete() { }); } - public void unSubscribeFromChannelsAsync(final String[] channels, final AsyncSuccess success){ + public void unSubscribeFromChannelsAsync(final String[] channels, final AsyncSuccessVoid success){ unSubscribeFromChannelsAsync(channels, AsyncUtils.createAsyncResult(success, null)); } - public void unSubscribeFromChannelsAsync(final String[] channels, final AsyncSuccess success, final AsyncError error){ + public void unSubscribeFromChannelsAsync(final String[] channels, final AsyncSuccessVoid success, final AsyncError error){ unSubscribeFromChannelsAsync(channels, AsyncUtils.createAsyncResult(success, error)); } } diff --git a/src/AndroidClient/androidchat/androidchat.iml b/src/AndroidClient/androidchat/androidchat.iml index 584b5cbf..0a82ebde 100644 --- a/src/AndroidClient/androidchat/androidchat.iml +++ b/src/AndroidClient/androidchat/androidchat.iml @@ -115,6 +115,7 @@ + diff --git a/src/AndroidClient/androidchat/src/main/java/servicestack/net/androidchat/Extensions.java b/src/AndroidClient/androidchat/src/main/java/servicestack/net/androidchat/Extensions.java index a1534337..59e0e1aa 100644 --- a/src/AndroidClient/androidchat/src/main/java/servicestack/net/androidchat/Extensions.java +++ b/src/AndroidClient/androidchat/src/main/java/servicestack/net/androidchat/Extensions.java @@ -6,11 +6,14 @@ import net.servicestack.android.AndroidServerEventsClient; import net.servicestack.android.AsyncUtils; +import net.servicestack.client.AsyncSuccess; +import net.servicestack.client.AsyncSuccessVoid; import net.servicestack.client.Utils; import net.servicestack.client.sse.ServerEventConnect; import net.servicestack.client.sse.ServerEventsClient; import net.servicestack.func.Func; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Objects; @@ -24,7 +27,7 @@ public class Extensions { - public static void updateChatHistory(AndroidServerEventsClient client, ChatCommandHandler cmdReceiver){ + public static void updateChatHistory(AndroidServerEventsClient client, ChatCommandHandler cmdReceiver, AsyncSuccessVoid cb){ client.getAndroidClient().getAsync(new GetChatHistory() .setChannels(Func.toList(client.getChannels())), @@ -37,22 +40,19 @@ public static void updateChatHistory(AndroidServerEventsClient client, ChatComma Objects.equals(x.getChannel(), channel))); } cmdReceiver.syncAdapter(); + cb.success(); }); } - public static void changeChannel(AndroidServerEventsClient client, String channel, ChatCommandHandler cmdReceiver){ - List currentChannels = Func.toList(client.getChannels()); - - if (cmdReceiver.getFullHistory().containsKey(channel) && currentChannels.contains(channel)){ + public static void changeChannel(AndroidServerEventsClient client, String channel, ChatCommandHandler cmdReceiver, AsyncSuccessVoid cb){ + if (cmdReceiver.getFullHistory().containsKey(channel) && Arrays.asList(client.getChannels()).contains(channel)){ cmdReceiver.changeChannel(channel); + cb.success(); } else { - - if (!currentChannels.contains(channel)) - currentChannels.add(channel); - - client.subscribeToChannels(Func.toArray(currentChannels, String.class)); - cmdReceiver.setCurrentChannel(channel); - updateChatHistory(client, cmdReceiver); + client.subscribeToChannelsAsync(new String[]{ channel }, () -> { + cmdReceiver.setCurrentChannel(channel); + updateChatHistory(client, cmdReceiver, cb); + }); } } diff --git a/src/AndroidClient/androidchat/src/main/java/servicestack/net/androidchat/MainActivity.java b/src/AndroidClient/androidchat/src/main/java/servicestack/net/androidchat/MainActivity.java index b2737f2f..4fe62a3c 100644 --- a/src/AndroidClient/androidchat/src/main/java/servicestack/net/androidchat/MainActivity.java +++ b/src/AndroidClient/androidchat/src/main/java/servicestack/net/androidchat/MainActivity.java @@ -52,9 +52,9 @@ public class MainActivity extends AppCompatActivity { "Announce Hello", "/cmd.announce Hello from Java Android", "Play YouTube", "/tv.watch https://youtu.be/u5CVsCnxyXg", "Background Image", "/css.background-image url(http://bit.ly/2lZxbHv)", - "Background Top", "/css.background$#top #0091ea", - "Background", "/css.background #fffde7", - "Background Bottom", "/css.background$#bottom #cccccc", + "Background Top", "/css.background$#top #86B951", + "Background Color", "/css.background #eceff1", + "Background Bottom", "/css.background$#bottom #91C654", "Logout", "/logout" ); @@ -93,8 +93,9 @@ protected void onCreate(Bundle savedInstanceState) { getClient() .setOnConnect(connectMsg -> { - Extensions.updateChatHistory(getClient(), cmdReceiver); - Extensions.updateUserProfile(connectMsg, mainActivity); + Extensions.updateChatHistory(getClient(), cmdReceiver, () -> { + Extensions.updateUserProfile(connectMsg, mainActivity); + }); }) .setOnCommand(command -> { if (command instanceof ServerEventJoin){ @@ -156,14 +157,15 @@ public boolean onChannelClick(MenuItem menuItem) List nChannels = Func.toList(getClient().getChannels()); nChannels.add(nChannel); UiHelpers.resetChannelDrawer(this, navigationView, Func.toArray(nChannels, String.class)); - Extensions.changeChannel(getClient(), nChannel, cmdReceiver); - cmdReceiver.syncAdapter(); + Extensions.changeChannel(getClient(), nChannel, cmdReceiver, () -> { + cmdReceiver.syncAdapter(); + }); } catch (Exception ex){ errors.add(ex); } }); } else { - Extensions.changeChannel(getClient(), itemText, cmdReceiver); + Extensions.changeChannel(getClient(), itemText, cmdReceiver, () -> {}); } drawerLayout.closeDrawer(navigationView); return true; From d8ecba7ae4605121f3d58d826a3dc95b3965df10 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sun, 5 Mar 2017 00:04:05 -0500 Subject: [PATCH 019/211] fix double entry layout bug + remove unused usersGroup menu --- .../java/servicestack/net/androidchat/MainActivity.java | 4 ---- .../androidchat/src/main/res/menu/drawer_view.xml | 9 --------- 2 files changed, 13 deletions(-) diff --git a/src/AndroidClient/androidchat/src/main/java/servicestack/net/androidchat/MainActivity.java b/src/AndroidClient/androidchat/src/main/java/servicestack/net/androidchat/MainActivity.java index 4fe62a3c..3bd0df3f 100644 --- a/src/AndroidClient/androidchat/src/main/java/servicestack/net/androidchat/MainActivity.java +++ b/src/AndroidClient/androidchat/src/main/java/servicestack/net/androidchat/MainActivity.java @@ -78,10 +78,6 @@ protected void onCreate(Bundle savedInstanceState) { InitDefaultBackground(chatBackground); navigationView.setTag(0); - navigationView.getMenu().clear(); //clear old inflated items. - navigationView.inflateMenu(R.menu.drawer_view); //inflate new items. - navigationView.inflateHeaderView(R.layout.nav_header); - rightDrawer.setTag(1); MessageListViewAdapter messageHistoryAdapter = new MessageListViewAdapter( diff --git a/src/AndroidClient/androidchat/src/main/res/menu/drawer_view.xml b/src/AndroidClient/androidchat/src/main/res/menu/drawer_view.xml index 6a9bf273..4c2267d0 100644 --- a/src/AndroidClient/androidchat/src/main/res/menu/drawer_view.xml +++ b/src/AndroidClient/androidchat/src/main/res/menu/drawer_view.xml @@ -6,13 +6,4 @@ - - - - - - - - - \ No newline at end of file From 1e71c33c6ff221a73112e820fa83097e3cd2c0fa Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sun, 5 Mar 2017 00:10:15 -0500 Subject: [PATCH 020/211] implement Utils.closeQuietly() --- .../servicestack/client/JsonServiceClient.java | 8 ++++---- .../main/java/net/servicestack/client/Utils.java | 15 +++++++++++++-- .../servicestack/client/JsonServiceClient.java | 8 ++++---- .../main/java/net/servicestack/client/Utils.java | 15 +++++++++++++-- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/JsonServiceClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/JsonServiceClient.java index 7e1f59e4..e9daeafb 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/JsonServiceClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/JsonServiceClient.java @@ -176,7 +176,7 @@ public HttpURLConnection createRequest(String requestUrl, String httpMethod, byt DataOutputStream wr = new DataOutputStream(req.getOutputStream()); wr.write(requestBody); wr.flush(); - wr.close(); + Utils.closeQuietly(wr); } return req; @@ -391,10 +391,10 @@ public TResponse send(String requestUrl, String httpMethod, byte[] r else { BufferedReader reader = new BufferedReader(new InputStreamReader(is)); TResponse response = resClass != null - ? (TResponse) getGson().fromJson(reader, resClass) - : (TResponse) getGson().fromJson(reader, resType); + ? (TResponse) getGson().fromJson(reader, resClass) + : (TResponse) getGson().fromJson(reader, resType); - reader.close(); + Utils.closeQuietly(reader); return response; } } catch (IOException e) { diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/Utils.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/Utils.java index 35221131..7f2798eb 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/Utils.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/Utils.java @@ -13,6 +13,7 @@ import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -524,7 +525,7 @@ public static String readToEnd(InputStream stream, final String charsetName) thr } String text = sb.toString(); - reader.close(); + closeQuietly(reader); return text; } @@ -557,7 +558,7 @@ public static byte[] readBytesToEnd(InputStream stream) throws IOException { } return bytes.toByteArray(); } finally { - bufferedStream.close(); + closeQuietly(bufferedStream); } } @@ -912,4 +913,14 @@ public static String unescapeHtml(String html){ .replace("'","\'") .replace(""","\""); } + + public static void closeQuietly(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) {} + } + } } diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/JsonServiceClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/JsonServiceClient.java index 7e1f59e4..e9daeafb 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/JsonServiceClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/JsonServiceClient.java @@ -176,7 +176,7 @@ public HttpURLConnection createRequest(String requestUrl, String httpMethod, byt DataOutputStream wr = new DataOutputStream(req.getOutputStream()); wr.write(requestBody); wr.flush(); - wr.close(); + Utils.closeQuietly(wr); } return req; @@ -391,10 +391,10 @@ public TResponse send(String requestUrl, String httpMethod, byte[] r else { BufferedReader reader = new BufferedReader(new InputStreamReader(is)); TResponse response = resClass != null - ? (TResponse) getGson().fromJson(reader, resClass) - : (TResponse) getGson().fromJson(reader, resType); + ? (TResponse) getGson().fromJson(reader, resClass) + : (TResponse) getGson().fromJson(reader, resType); - reader.close(); + Utils.closeQuietly(reader); return response; } } catch (IOException e) { diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/Utils.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/Utils.java index 35221131..7f2798eb 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/Utils.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/Utils.java @@ -13,6 +13,7 @@ import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -524,7 +525,7 @@ public static String readToEnd(InputStream stream, final String charsetName) thr } String text = sb.toString(); - reader.close(); + closeQuietly(reader); return text; } @@ -557,7 +558,7 @@ public static byte[] readBytesToEnd(InputStream stream) throws IOException { } return bytes.toByteArray(); } finally { - bufferedStream.close(); + closeQuietly(bufferedStream); } } @@ -912,4 +913,14 @@ public static String unescapeHtml(String html){ .replace("'","\'") .replace(""","\""); } + + public static void closeQuietly(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) {} + } + } } From fec67b2f2181971a42ba29f1ee666c5e64621e0a Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sun, 5 Mar 2017 00:10:43 -0500 Subject: [PATCH 021/211] rename EventStream.close() to more appropriate cancel() --- .../android/AndroidServerEventsClient.java | 13 ++++++++----- .../net/servicestack/client/sse/EventStream.java | 6 ++++-- .../servicestack/client/sse/ServerEventsClient.java | 2 +- .../net/servicestack/client/sse/EventStream.java | 6 ++++-- .../servicestack/client/sse/ServerEventsClient.java | 2 +- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java index dbb3b7ef..5fd6b2e1 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServerEventsClient.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.concurrent.TimeUnit; import okhttp3.Call; import okhttp3.Callback; @@ -47,7 +48,8 @@ public AndroidServerEventsClient(String baseUri, String... channels) { this.serviceClient = new AndroidServiceClient(this.baseUri); client = new OkHttpClient.Builder() - .cookieJar(new JavaNetCookieJar(CookieHandler.getDefault())) + .cookieJar(new JavaNetCookieJar(CookieHandler.getDefault())) //sync cookies with Android HTTP + .readTimeout(0, TimeUnit.MILLISECONDS) //disable Read Timeout on long poll /event-stream .build(); } @@ -99,9 +101,10 @@ protected InputStream getInputStream(URL streamUri) throws IOException { } @Override - public void close() { - if (call == null) return; - call.cancel(); + public void cancel() { + if (call != null){ + call.cancel(); + } } @Override @@ -129,7 +132,7 @@ protected int readFromStream(InputStream inputStream, byte[] buffer) throws IOEx @Override protected synchronized void stopBackgroundThread() { if (bgThread != null){ - bgEventStream.close(); + bgEventStream.cancel(); try { bgThread.join(100); } catch (InterruptedException ignore) {} diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java index 9a914d06..dfc5bafe 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java @@ -28,18 +28,19 @@ protected InputStream getInputStream(URL streamUri) throws IOException { return new BufferedInputStream(req.getInputStream()); } - public void close(){ + public void cancel(){ } @Override public void run() { + InputStream is = null; try { if (client.running.get()) return; client.running.set(true); URL streamUri = new URL(client.getEventStreamUri()); - InputStream is = getInputStream(streamUri); + is = getInputStream(streamUri); client.errorsCount.set(0); readStream(is); } catch (InterruptedException ie){ @@ -50,6 +51,7 @@ public void run() { Log.e("Error reading from event-stream, continuous errors: " + client.errorsCount.incrementAndGet(), e); Log.e(Utils.getStackTrace(e)); } finally { + Utils.closeQuietly(is); client.running.set(false); } diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index 58244d27..459fbcc9 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -274,7 +274,7 @@ public String getConnectionDisplayName() { protected synchronized void stopBackgroundThread() { if (bgThread != null){ - bgEventStream.close(); + bgEventStream.cancel(); bgThread.interrupt(); //notify the bgThread to exit try { bgThread.join(); diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java index 9a914d06..dfc5bafe 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java @@ -28,18 +28,19 @@ protected InputStream getInputStream(URL streamUri) throws IOException { return new BufferedInputStream(req.getInputStream()); } - public void close(){ + public void cancel(){ } @Override public void run() { + InputStream is = null; try { if (client.running.get()) return; client.running.set(true); URL streamUri = new URL(client.getEventStreamUri()); - InputStream is = getInputStream(streamUri); + is = getInputStream(streamUri); client.errorsCount.set(0); readStream(is); } catch (InterruptedException ie){ @@ -50,6 +51,7 @@ public void run() { Log.e("Error reading from event-stream, continuous errors: " + client.errorsCount.incrementAndGet(), e); Log.e(Utils.getStackTrace(e)); } finally { + Utils.closeQuietly(is); client.running.set(false); } diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index 58244d27..459fbcc9 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -274,7 +274,7 @@ public String getConnectionDisplayName() { protected synchronized void stopBackgroundThread() { if (bgThread != null){ - bgEventStream.close(); + bgEventStream.cancel(); bgThread.interrupt(); //notify the bgThread to exit try { bgThread.join(); From ecd6827fc3c44564103ccfc7a6a50908666e154b Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sun, 5 Mar 2017 00:22:31 -0500 Subject: [PATCH 022/211] bump to v1.0.30 --- src/AndroidClient/android/build.gradle | 2 +- src/AndroidClient/client/build.gradle | 2 +- src/AndroidClient/client/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AndroidClient/android/build.gradle b/src/AndroidClient/android/build.gradle index f6844453..e91a5df8 100644 --- a/src/AndroidClient/android/build.gradle +++ b/src/AndroidClient/android/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.library' apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' -version = "1.0.29" +version = "1.0.30" dependencies { compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/src/AndroidClient/client/build.gradle b/src/AndroidClient/client/build.gradle index 6c904552..9eb69a2e 100644 --- a/src/AndroidClient/client/build.gradle +++ b/src/AndroidClient/client/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' -version = "1.0.29" +version = "1.0.30" dependencies { compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/src/AndroidClient/client/pom.xml b/src/AndroidClient/client/pom.xml index fa4d04e6..3ddc7da8 100644 --- a/src/AndroidClient/client/pom.xml +++ b/src/AndroidClient/client/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.servicestack client - 1.0.29 + 1.0.30 ServiceStack.Client A client library to call your ServiceStack webservices. https://github.com/ServiceStack/ServiceStack.Java From 68e345f22fbb31d0d29497a7b9856e279305ad9d Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Mon, 6 Mar 2017 21:53:35 -0500 Subject: [PATCH 023/211] Force Global Receiver to share same name as type to match behavior with other SSE clients --- .../servicestack/client/sse/ServerEventsClient.java | 3 ++- .../servicestack/client/sse/ServerEventsClient.java | 3 ++- .../servicestack/client/ServerEventClientTests.java | 2 +- .../net/servicestack/client/TestGlobalReceiver.java | 12 ++++++------ 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index 459fbcc9..58fa14d8 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -224,7 +224,8 @@ public void execute(ServerEventsClient client, ServerEventMessage msg) { Class requestType = args[0]; - if (target.equals(requestType.getSimpleName())) { + if (target.equals(requestType.getSimpleName()) && + mi.getName().toLowerCase().equals(target.toLowerCase())) { Object request = !Utils.isNullOrEmpty(msg.getJson()) ? JsonUtils.fromJson(msg.getJson(), requestType) : requestType.newInstance(); diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index 459fbcc9..58fa14d8 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -224,7 +224,8 @@ public void execute(ServerEventsClient client, ServerEventMessage msg) { Class requestType = args[0]; - if (target.equals(requestType.getSimpleName())) { + if (target.equals(requestType.getSimpleName()) && + mi.getName().toLowerCase().equals(target.toLowerCase())) { Object request = !Utils.isNullOrEmpty(msg.getJson()) ? JsonUtils.fromJson(msg.getJson(), requestType) : requestType.newInstance(); diff --git a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java index 4186561d..eed36930 100644 --- a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java +++ b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java @@ -480,7 +480,7 @@ public void test_Does_send_message_to_global_receiver() throws Exception { Thread.sleep(100); } - CustomType foo = TestGlobalReceiver.FooMethodReceived; + CustomType foo = TestGlobalReceiver.CustomTypeReceived; assertNotNull(foo); assertEquals(1, foo.getId().intValue()); assertEquals("Foo", foo.getName()); diff --git a/src/AndroidClient/client/src/test/java/net/servicestack/client/TestGlobalReceiver.java b/src/AndroidClient/client/src/test/java/net/servicestack/client/TestGlobalReceiver.java index 72b9846e..d10118c5 100644 --- a/src/AndroidClient/client/src/test/java/net/servicestack/client/TestGlobalReceiver.java +++ b/src/AndroidClient/client/src/test/java/net/servicestack/client/TestGlobalReceiver.java @@ -10,18 +10,18 @@ */ public class TestGlobalReceiver extends ServerEventReceiver { - public static CustomType FooMethodReceived; + public static CustomType CustomTypeReceived; public static CustomType NoSuchMethodReceived; public static String NoSuchMethodSelector; - public static SetterType AnyNamedSetterReceived; + public static SetterType SetterTypeReceived; - public void setAnyNamedSetter(SetterType value) { - AnyNamedSetterReceived = value; + public void setterType(SetterType value) { + SetterTypeReceived = value; } - public void anyNamedMethod(CustomType request) + public void customType(CustomType request) { - FooMethodReceived = request; + CustomTypeReceived = request; } @Override From b9d784d0d78a05bec988b22d1c04b9415a022e2d Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Mon, 6 Mar 2017 21:56:57 -0500 Subject: [PATCH 024/211] clean up tests --- .../android/ServerEventClientTests.java | 8 ++------ .../servicestack/android/TestGlobalReceiver.java | 12 ++++++------ src/AndroidClient/androidchat/androidchat.iml | 16 ++++++++-------- src/AndroidClient/app/app.iml | 16 ++++++++-------- .../client/ServerEventClientTests.java | 6 +----- src/AndroidClient/techstacks/techstacks.iml | 16 ++++++++-------- 6 files changed, 33 insertions(+), 41 deletions(-) diff --git a/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java index 55910dd2..fa0adf2d 100644 --- a/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java +++ b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java @@ -226,8 +226,6 @@ public void execute(ServerEventConnect e) { connectMsg = Func.first(connectMsgs); joinMsg = Func.first(Func.ofType(commands, ServerEventJoin.class)); - - Utils.readToEnd(connectMsg.getUnRegisterUrl()); } while (commands.size() < 2) { @@ -365,7 +363,6 @@ public void execute(ServerEventMessage e) { assertTrue(chatMsg.getId() > 0); assertEquals(info1.getUserId(), chatMsg.getFromUserId()); assertEquals(info1.getDisplayName(), chatMsg.getFromName()); - assertEquals(info1.getDisplayName(), chatMsg.getFromName()); } assertEquals(1, msgs1.size()); @@ -388,7 +385,6 @@ public void execute(ServerEventMessage e) { assertTrue(chatMsg.getId() > 0); assertEquals(info2.getUserId(), chatMsg.getFromUserId()); assertEquals(info2.getDisplayName(), chatMsg.getFromName()); - assertEquals(info2.getDisplayName(), chatMsg.getFromName()); } assertEquals(2, msgs1.size()); @@ -613,7 +609,7 @@ public void execute(ServerEventMessage e) { Thread.sleep(100); } - CustomType foo = TestGlobalReceiver.FooMethodReceived; + CustomType foo = TestGlobalReceiver.CustomTypeReceived; assertNotNull(foo); assertEquals(1, foo.getId().intValue()); assertEquals("Foo", foo.getName()); @@ -643,7 +639,7 @@ public void execute(ServerEventMessage e) { Thread.sleep(100); } - SetterType foo = TestGlobalReceiver.AnyNamedSetterReceived; + SetterType foo = TestGlobalReceiver.SetterTypeReceived; assertNotNull(foo); assertEquals(1, foo.getId().intValue()); assertEquals("Foo", foo.getName()); diff --git a/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestGlobalReceiver.java b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestGlobalReceiver.java index 319c80c4..19fe2d88 100644 --- a/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestGlobalReceiver.java +++ b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/TestGlobalReceiver.java @@ -11,18 +11,18 @@ */ public class TestGlobalReceiver extends ServerEventReceiver { - public static CustomType FooMethodReceived; + public static CustomType CustomTypeReceived; public static CustomType NoSuchMethodReceived; public static String NoSuchMethodSelector; - public static SetterType AnyNamedSetterReceived; + public static SetterType SetterTypeReceived; - public void setAnyNamedSetter(SetterType value) { - AnyNamedSetterReceived = value; + public void setterType(SetterType value) { + SetterTypeReceived = value; } - public void anyNamedMethod(CustomType request) + public void customType(CustomType request) { - FooMethodReceived = request; + CustomTypeReceived = request; } @Override diff --git a/src/AndroidClient/androidchat/androidchat.iml b/src/AndroidClient/androidchat/androidchat.iml index 0a82ebde..fdcf27bd 100644 --- a/src/AndroidClient/androidchat/androidchat.iml +++ b/src/AndroidClient/androidchat/androidchat.iml @@ -67,14 +67,6 @@ - - - - - - - - @@ -83,6 +75,14 @@ + + + + + + + + diff --git a/src/AndroidClient/app/app.iml b/src/AndroidClient/app/app.iml index b591e10f..8834e450 100644 --- a/src/AndroidClient/app/app.iml +++ b/src/AndroidClient/app/app.iml @@ -67,14 +67,6 @@ - - - - - - - - @@ -83,6 +75,14 @@ + + + + + + + + diff --git a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java index eed36930..b19270cc 100644 --- a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java +++ b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java @@ -160,8 +160,6 @@ public void test_Does_fire_all_callbacks() throws Exception { connectMsg = Func.first(connectMsgs); joinMsg = Func.first(Func.ofType(commands, ServerEventJoin.class)); - - Utils.readToEnd(connectMsg.getUnRegisterUrl()); } while (commands.size() < 2) { @@ -273,7 +271,6 @@ public void test_Does_receive_messages() throws Exception { assertTrue(chatMsg.getId() > 0); assertEquals(info1.getUserId(), chatMsg.getFromUserId()); assertEquals(info1.getDisplayName(), chatMsg.getFromName()); - assertEquals(info1.getDisplayName(), chatMsg.getFromName()); } assertEquals(1, msgs1.size()); @@ -296,7 +293,6 @@ public void test_Does_receive_messages() throws Exception { assertTrue(chatMsg.getId() > 0); assertEquals(info2.getUserId(), chatMsg.getFromUserId()); assertEquals(info2.getDisplayName(), chatMsg.getFromName()); - assertEquals(info2.getDisplayName(), chatMsg.getFromName()); } assertEquals(2, msgs1.size()); @@ -504,7 +500,7 @@ public void test_Does_set_properties_on_global_receiver() throws Exception { Thread.sleep(100); } - SetterType foo = TestGlobalReceiver.AnyNamedSetterReceived; + SetterType foo = TestGlobalReceiver.SetterTypeReceived; assertNotNull(foo); assertEquals(1, foo.getId().intValue()); assertEquals("Foo", foo.getName()); diff --git a/src/AndroidClient/techstacks/techstacks.iml b/src/AndroidClient/techstacks/techstacks.iml index b78bb195..46c73ede 100644 --- a/src/AndroidClient/techstacks/techstacks.iml +++ b/src/AndroidClient/techstacks/techstacks.iml @@ -67,14 +67,6 @@ - - - - - - - - @@ -83,6 +75,14 @@ + + + + + + + + From 944cd72c0942196835ba0978dcbf3f7e0b80baed Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Mon, 6 Mar 2017 22:54:40 -0500 Subject: [PATCH 025/211] remove unnecesary sleep --- .../java/net/servicestack/android/ServerEventClientTests.java | 2 -- .../java/net/servicestack/client/ServerEventClientTests.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java index fa0adf2d..ff800abc 100644 --- a/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java +++ b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java @@ -816,8 +816,6 @@ public void execute(ServerEventMessage e) { assertEquals(3, msgsABC.size()); assertEquals(4, msgsABCD.size()); - Thread.sleep(1000); - System.out.println("Publishing Msg Batch #2 ..."); postChat(clientA, "#5 hello to A", "A"); postChat(clientA, "#6 hello to B", "B"); diff --git a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java index b19270cc..a819a404 100644 --- a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java +++ b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java @@ -644,8 +644,6 @@ public void test_Does_receive_messages_on_to_clients_subscribed_on_multiple_chan assertEquals(3, msgsABC.size()); assertEquals(4, msgsABCD.size()); - Thread.sleep(1000); - System.out.println("Publishing Msg Batch #2 ..."); postChat(clientA, "#5 hello to A", "A"); postChat(clientA, "#6 hello to B", "B"); From 47d4ee4d4bacd044789ffdac772b0f60cb8a14b6 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Thu, 9 Mar 2017 21:04:26 -0500 Subject: [PATCH 026/211] Rename Each to Action so can be reused --- .../java/net/servicestack/func/{Each.java => Action.java} | 2 +- .../android/src/main/java/net/servicestack/func/Func.java | 4 ++-- .../java/net/servicestack/func/{Each.java => Action.java} | 2 +- .../client/src/main/java/net/servicestack/func/Func.java | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) rename src/AndroidClient/android/src/main/java/net/servicestack/func/{Each.java => Action.java} (86%) rename src/AndroidClient/client/src/main/java/net/servicestack/func/{Each.java => Action.java} (86%) diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/func/Each.java b/src/AndroidClient/android/src/main/java/net/servicestack/func/Action.java similarity index 86% rename from src/AndroidClient/android/src/main/java/net/servicestack/func/Each.java rename to src/AndroidClient/android/src/main/java/net/servicestack/func/Action.java index 167f9e40..3d2367f2 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/func/Each.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/func/Action.java @@ -3,6 +3,6 @@ package net.servicestack.func; -public interface Each { +public interface Action { public void apply(T t); } diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/func/Func.java b/src/AndroidClient/android/src/main/java/net/servicestack/func/Func.java index 749bdcc1..df72f0e4 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/func/Func.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/func/Func.java @@ -159,11 +159,11 @@ public static ArrayList mapi(Iterable xs, FunctionIndex f) { return to; } - public static void each(T[] xs, Each f) { + public static void each(T[] xs, Action f) { each(toList(xs), f); } - public static void each(Iterable xs, Each f) { + public static void each(Iterable xs, Action f) { if (xs == null) return; for (T x : xs) { f.apply(x); diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/func/Each.java b/src/AndroidClient/client/src/main/java/net/servicestack/func/Action.java similarity index 86% rename from src/AndroidClient/client/src/main/java/net/servicestack/func/Each.java rename to src/AndroidClient/client/src/main/java/net/servicestack/func/Action.java index 167f9e40..3d2367f2 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/func/Each.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/func/Action.java @@ -3,6 +3,6 @@ package net.servicestack.func; -public interface Each { +public interface Action { public void apply(T t); } diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/func/Func.java b/src/AndroidClient/client/src/main/java/net/servicestack/func/Func.java index 749bdcc1..df72f0e4 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/func/Func.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/func/Func.java @@ -159,11 +159,11 @@ public static ArrayList mapi(Iterable xs, FunctionIndex f) { return to; } - public static void each(T[] xs, Each f) { + public static void each(T[] xs, Action f) { each(toList(xs), f); } - public static void each(Iterable xs, Each f) { + public static void each(Iterable xs, Action f) { if (xs == null) return; for (T x : xs) { f.apply(x); From 01c086be1f20f2b4e24469b9f16b0cd618cec50d Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Thu, 9 Mar 2017 21:05:23 -0500 Subject: [PATCH 027/211] Implement addListener/removeListener/raiseEvent to handle custom SSE triggers --- .../android/ServerEventClientTests.java | 58 ++++++++++++++++++- .../servicestack/client/sse/EventStream.java | 2 + .../client/sse/ServerEventsClient.java | 45 ++++++++++++++ .../servicestack/client/sse/EventStream.java | 2 + .../client/sse/ServerEventsClient.java | 45 ++++++++++++++ .../client/ServerEventClientTests.java | 42 ++++++++++++++ 6 files changed, 193 insertions(+), 1 deletion(-) diff --git a/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java index ff800abc..952788dd 100644 --- a/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java +++ b/src/AndroidClient/android/src/androidTest/java/net/servicestack/android/ServerEventClientTests.java @@ -25,7 +25,9 @@ import net.servicestack.client.sse.ServerEventUser; import net.servicestack.client.sse.ServerEventsClient; import net.servicestack.client.sse.SingletonInstanceResolver; +import net.servicestack.func.Action; import net.servicestack.func.Func; +import net.servicestack.func.Predicate; import java.util.ArrayList; import java.util.HashMap; @@ -1115,4 +1117,58 @@ public void execute(ServerEventMessage e) { assertTrue(client2.getEventStreamUri().endsWith("?channels=B")); } } -} + + @Test + public void test_Does_fire_multiple_listeners_for_custom_trigger() throws Exception { + final List msgs1 = new ArrayList<>(); + final List msgs2 = new ArrayList<>(); + + Action handler = new Action() { + @Override + public void apply(ServerEventMessage e) { + msgs1.add(e); + } + }; + + try (ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") + .addListener("customEvent", handler) + .addListener("customEvent", new Action() { + @Override + public void apply(ServerEventMessage e) { + msgs2.add(e); + } + }) + .start() + .waitTillConnected(); + ServerEventsClient client2 = createServerEventsClient("http://chat.servicestack.net") + .start() + .waitTillConnected()) { + + postRaw(client2, "trigger.customEvent", "arg"); + + while (msgs1.size() < 1 || msgs2.size() < 1) { + Thread.sleep(100); + } + + assertEquals(1, msgs1.size()); + assertEquals(1, msgs2.size()); + + client1.removeListener("customEvent", handler); + + postRaw(client2, "trigger.customEvent", "arg"); + + while (msgs1.size() < 1 || msgs2.size() < 2) { + Thread.sleep(100); + } + + assertEquals(1, msgs1.size()); + assertEquals(2, msgs2.size()); + + assertTrue(Func.all(Func.concat(msgs1, msgs2), new Predicate() { + @Override + public boolean apply(ServerEventMessage msg) { + return "arg".equals(JsonUtils.fromJson(msg.getJson(), String.class)); + } + })); + } + }} diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java index dfc5bafe..46e675d7 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/EventStream.java @@ -182,6 +182,8 @@ protected void processEventMessage(ServerEventMessage e) { cb.execute(this.client, e); } } + } else if ("trigger".equals(e.getOp())){ + client.onTriggerReceived(e); } ServerEventCallback receiver = client.getNamedReceivers().get(e.getOp()); diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index 58fa14d8..b5e3d322 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -8,6 +8,7 @@ import net.servicestack.client.JsonUtils; import net.servicestack.client.Log; import net.servicestack.client.Utils; +import net.servicestack.func.Action; import net.servicestack.func.Func; import net.servicestack.func.Function; @@ -47,6 +48,7 @@ public class ServerEventsClient implements Closeable { protected Map handlers; protected Map namedReceivers; + protected Map>> listeners; protected ServerEventConnectCallback onConnect; protected ServerEventMessageCallback onMessage; @@ -76,6 +78,7 @@ public ServerEventsClient(String baseUri, String... channels) { this.handlers = new HashMap<>(); this.namedReceivers = new HashMap<>(); + this.listeners = new HashMap<>(); } public ServerEventsClient(String baseUrl, String channel) { @@ -386,6 +389,17 @@ private void onCommandReceived(ServerEventMessage e) { onCommand.execute(e); } + protected void onTriggerReceived(ServerEventMessage e) { + if (Log.isDebugEnabled()) + Log.d("[SSE-CLIENT] OnTriggerReceived: (" + + e.getClass().getSimpleName() + ") #" + + e.getEventId() + " on #" + + getConnectionDisplayName() + " (" + + Utils.join(channels, ",") + ")"); + + raiseEvent(e.getTarget(), e); + } + private void onHeartbeatReceived(ServerEventMessage e) { if (Log.isDebugEnabled()) Log.d("[SSE-CLIENT] OnHeartbeatReceived: (" @@ -436,6 +450,37 @@ private void onConnectReceived() { startNewHeartbeat(); } + public synchronized ServerEventsClient addListener(String eventName, Action handler){ + List> handlers = listeners.get(eventName); + if (handlers == null){ + handlers = new ArrayList<>(); + listeners.put(eventName, handlers); + } + handlers.add(handler); + return this; + } + + public synchronized ServerEventsClient removeListener(String eventName, Action handler){ + List> handlers = listeners.get(eventName); + if (handlers != null){ + handlers.remove(handler); + } + return this; + } + + public synchronized void raiseEvent(String eventName, ServerEventMessage message) { + List> handlers = listeners.get(eventName); + if (handlers != null){ + for (Action handler : handlers) { + try { + handler.apply(message); + } catch (Exception e) { + Log.e("Error whilst executing '" + eventName + "' handler", e); + } + } + } + } + Timer heratbeatTimer; private void startNewHeartbeat() { diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java index dfc5bafe..46e675d7 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/EventStream.java @@ -182,6 +182,8 @@ protected void processEventMessage(ServerEventMessage e) { cb.execute(this.client, e); } } + } else if ("trigger".equals(e.getOp())){ + client.onTriggerReceived(e); } ServerEventCallback receiver = client.getNamedReceivers().get(e.getOp()); diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index 58fa14d8..b5e3d322 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -8,6 +8,7 @@ import net.servicestack.client.JsonUtils; import net.servicestack.client.Log; import net.servicestack.client.Utils; +import net.servicestack.func.Action; import net.servicestack.func.Func; import net.servicestack.func.Function; @@ -47,6 +48,7 @@ public class ServerEventsClient implements Closeable { protected Map handlers; protected Map namedReceivers; + protected Map>> listeners; protected ServerEventConnectCallback onConnect; protected ServerEventMessageCallback onMessage; @@ -76,6 +78,7 @@ public ServerEventsClient(String baseUri, String... channels) { this.handlers = new HashMap<>(); this.namedReceivers = new HashMap<>(); + this.listeners = new HashMap<>(); } public ServerEventsClient(String baseUrl, String channel) { @@ -386,6 +389,17 @@ private void onCommandReceived(ServerEventMessage e) { onCommand.execute(e); } + protected void onTriggerReceived(ServerEventMessage e) { + if (Log.isDebugEnabled()) + Log.d("[SSE-CLIENT] OnTriggerReceived: (" + + e.getClass().getSimpleName() + ") #" + + e.getEventId() + " on #" + + getConnectionDisplayName() + " (" + + Utils.join(channels, ",") + ")"); + + raiseEvent(e.getTarget(), e); + } + private void onHeartbeatReceived(ServerEventMessage e) { if (Log.isDebugEnabled()) Log.d("[SSE-CLIENT] OnHeartbeatReceived: (" @@ -436,6 +450,37 @@ private void onConnectReceived() { startNewHeartbeat(); } + public synchronized ServerEventsClient addListener(String eventName, Action handler){ + List> handlers = listeners.get(eventName); + if (handlers == null){ + handlers = new ArrayList<>(); + listeners.put(eventName, handlers); + } + handlers.add(handler); + return this; + } + + public synchronized ServerEventsClient removeListener(String eventName, Action handler){ + List> handlers = listeners.get(eventName); + if (handlers != null){ + handlers.remove(handler); + } + return this; + } + + public synchronized void raiseEvent(String eventName, ServerEventMessage message) { + List> handlers = listeners.get(eventName); + if (handlers != null){ + for (Action handler : handlers) { + try { + handler.apply(message); + } catch (Exception e) { + Log.e("Error whilst executing '" + eventName + "' handler", e); + } + } + } + } + Timer heratbeatTimer; private void startNewHeartbeat() { diff --git a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java index a819a404..74015665 100644 --- a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java +++ b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java @@ -10,6 +10,7 @@ import net.servicestack.client.sse.ServerEventUser; import net.servicestack.client.sse.ServerEventsClient; import net.servicestack.client.sse.SingletonInstanceResolver; +import net.servicestack.func.Action; import net.servicestack.func.Func; import java.util.ArrayList; @@ -902,4 +903,45 @@ public void test_Can_unsubscribe_from_channels_whilst_connected() throws Excepti assertTrue(client2.getEventStreamUri().endsWith("?channels=B")); } } + + public void test_Does_fire_multiple_listeners_for_custom_trigger() throws Exception { + List msgs1 = new ArrayList<>(); + List msgs2 = new ArrayList<>(); + + Action handler = msgs1::add; + + try (ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") + .addListener("customEvent", handler) + .addListener("customEvent", msgs2::add) + .start() + .waitTillConnected(); + ServerEventsClient client2 = createServerEventsClient("http://chat.servicestack.net") + .start() + .waitTillConnected()) { + + postRaw(client2, "trigger.customEvent", "arg"); + + while (msgs1.size() < 1 || msgs2.size() < 1) { + Thread.sleep(100); + } + + assertEquals(1, msgs1.size()); + assertEquals(1, msgs2.size()); + + client1.removeListener("customEvent", handler); + + postRaw(client2, "trigger.customEvent", "arg"); + + while (msgs1.size() < 1 || msgs2.size() < 2) { + Thread.sleep(100); + } + + assertEquals(1, msgs1.size()); + assertEquals(2, msgs2.size()); + + assertTrue(Func.all(Func.concat(msgs1, msgs2), msg -> + "arg".equals(JsonUtils.fromJson(msg.getJson(), String.class)))); + } + } + } From 8bb1fdd784b80c3ee0456931dcdfca957465d850 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Thu, 16 Mar 2017 17:14:39 -0400 Subject: [PATCH 028/211] Add support links --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 4861f10a..152d946d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +Join the [ServiceStack Google+ Community](https://plus.google.com/communities/112445368900682590445) or follow [@ServiceStack](https://twitter.com/servicestack) +for updates, or [StackOverflow](http://stackoverflow.com/questions/ask) or the [Customer Support Forums](https://forums.servicestack.net/) for support. + # ServiceStack.Java This repository contains the source for ServiceStack plugins for the leading Android Studio, IntelliJ and Eclipse Java IDE's providing Java developers a highly productive development experience for consuming Typed ServiceStack Services by leveraging [Add ServiceStack Reference](https://github.com/ServiceStack/ServiceStack/wiki/Add-ServiceStack-Reference) directly within their IDE! From 711a77b5986675ebd4a422c8a7633db0efa61c26 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Thu, 16 Mar 2017 17:20:03 -0400 Subject: [PATCH 029/211] shorter links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 152d946d..c3b63144 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -Join the [ServiceStack Google+ Community](https://plus.google.com/communities/112445368900682590445) or follow [@ServiceStack](https://twitter.com/servicestack) -for updates, or [StackOverflow](http://stackoverflow.com/questions/ask) or the [Customer Support Forums](https://forums.servicestack.net/) for support. +Follow [@ServiceStack](https://twitter.com/servicestack) or join the [Google+ Community](https://plus.google.com/communities/112445368900682590445) +for updates, or [StackOverflow](http://stackoverflow.com/questions/ask) or the [Customer Forums](https://forums.servicestack.net/) for support. # ServiceStack.Java From bd8bfd06e96a73271ae13d94518c2a3f2f8f03a4 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Tue, 21 Mar 2017 02:03:12 -0400 Subject: [PATCH 030/211] Add distinct OnJoin/OnLeave/OnUpdate commands to match TypeScript SSE Client --- src/AndroidClient/app/app.iml | 16 ++--- .../client/sse/ServerEventJoinCallback.java | 6 ++ .../client/sse/ServerEventLeaveCallback.java | 6 ++ .../client/sse/ServerEventUpdateCallback.java | 5 ++ .../client/sse/ServerEventsClient.java | 69 ++++++++++++++++++- .../client/ServerEventClientTests.java | 18 ++--- src/AndroidClient/kotlin/kotlin.iml | 16 ++--- .../techstackskotlin/techstackskotlin.iml | 16 ++--- 8 files changed, 114 insertions(+), 38 deletions(-) create mode 100644 src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventJoinCallback.java create mode 100644 src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventLeaveCallback.java create mode 100644 src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventUpdateCallback.java diff --git a/src/AndroidClient/app/app.iml b/src/AndroidClient/app/app.iml index 8834e450..b591e10f 100644 --- a/src/AndroidClient/app/app.iml +++ b/src/AndroidClient/app/app.iml @@ -67,14 +67,6 @@ - - - - - - - - @@ -83,6 +75,14 @@ + + + + + + + + diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventJoinCallback.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventJoinCallback.java new file mode 100644 index 00000000..7568f56e --- /dev/null +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventJoinCallback.java @@ -0,0 +1,6 @@ +package net.servicestack.client.sse; + +public interface ServerEventJoinCallback { + void execute(ServerEventJoin e); +} + diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventLeaveCallback.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventLeaveCallback.java new file mode 100644 index 00000000..07517608 --- /dev/null +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventLeaveCallback.java @@ -0,0 +1,6 @@ +package net.servicestack.client.sse; + +public interface ServerEventLeaveCallback { + void execute(ServerEventLeave e); +} + diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventUpdateCallback.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventUpdateCallback.java new file mode 100644 index 00000000..36f9bdae --- /dev/null +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventUpdateCallback.java @@ -0,0 +1,5 @@ +package net.servicestack.client.sse; + +public interface ServerEventUpdateCallback { + void execute(ServerEventUpdate e); +} diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index b5e3d322..051f0e12 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -52,6 +52,9 @@ public class ServerEventsClient implements Closeable { protected ServerEventConnectCallback onConnect; protected ServerEventMessageCallback onMessage; + protected ServerEventJoinCallback onJoin; + protected ServerEventLeaveCallback onLeave; + protected ServerEventUpdateCallback onUpdate; protected ServerEventMessageCallback onCommand; protected ServerEventMessageCallback onHeartbeat; protected ExceptionCallback onException; @@ -156,6 +159,21 @@ public ServerEventsClient setOnMessage(ServerEventMessageCallback onMessage) { return this; } + public ServerEventsClient setOnJoin(ServerEventJoinCallback onJoin) { + this.onJoin = onJoin; + return this; + } + + public ServerEventsClient setOnLeave(ServerEventLeaveCallback onLeave) { + this.onLeave = onLeave; + return this; + } + + public ServerEventsClient setOnUpdate(ServerEventUpdateCallback onUpdate) { + this.onUpdate = onUpdate; + return this; + } + public ServerEventsClient setOnCommand(ServerEventMessageCallback onCommand) { this.onCommand = onCommand; return this; @@ -377,6 +395,42 @@ private synchronized void internalStop() { stopBackgroundThread(); } + private void onJoinReceived(ServerEventJoin e) { + if (Log.isDebugEnabled()) + Log.d("[SSE-CLIENT] OnJoinReceived: (" + + e.getClass().getSimpleName() + ") #" + + e.getEventId() + " on #" + + getConnectionDisplayName() + " (" + + Utils.join(channels, ",") + ")"); + + if (onJoin != null) + onJoin.execute(e); + } + + private void onLeaveReceived(ServerEventLeave e) { + if (Log.isDebugEnabled()) + Log.d("[SSE-CLIENT] OnLeaveReceived: (" + + e.getClass().getSimpleName() + ") #" + + e.getEventId() + " on #" + + getConnectionDisplayName() + " (" + + Utils.join(channels, ",") + ")"); + + if (onLeave != null) + onLeave.execute(e); + } + + private void onUpdateReceived(ServerEventUpdate e) { + if (Log.isDebugEnabled()) + Log.d("[SSE-CLIENT] OnUpdateReceived: (" + + e.getClass().getSimpleName() + ") #" + + e.getEventId() + " on #" + + getConnectionDisplayName() + " (" + + Utils.join(channels, ",") + ")"); + + if (onUpdate != null) + onUpdate.execute(e); + } + private void onCommandReceived(ServerEventMessage e) { if (Log.isDebugEnabled()) Log.d("[SSE-CLIENT] OnCommandReceived: (" @@ -570,15 +624,24 @@ protected void processOnConnectMessage(ServerEventMessage e) { } protected void processOnJoinMessage(ServerEventMessage e) { - onCommandReceived(new ServerEventJoin().populate(e, JsonUtils.toJsonObject(e.getJson()))); + ServerEventJoin m = new ServerEventJoin(); + m.populate(e, JsonUtils.toJsonObject(e.getJson())); + onJoinReceived(m); + onCommandReceived(m); } protected void processOnLeaveMessage(ServerEventMessage e) { - onCommandReceived(new ServerEventLeave().populate(e, JsonUtils.toJsonObject(e.getJson()))); + ServerEventLeave m = new ServerEventLeave(); + m.populate(e, JsonUtils.toJsonObject(e.getJson())); + onLeaveReceived(m); + onCommandReceived(m); } protected void processOnUpdateMessage(ServerEventMessage e) { - onCommandReceived(new ServerEventUpdate().populate(e, JsonUtils.toJsonObject(e.getJson()))); + ServerEventUpdate m = new ServerEventUpdate(); + m.populate(e, JsonUtils.toJsonObject(e.getJson())); + onUpdateReceived(m); + onCommandReceived(m); } protected void processOnHeartbeatMessage(ServerEventMessage e) { diff --git a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java index 74015665..e43997bc 100644 --- a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java +++ b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java @@ -83,19 +83,15 @@ public void test_Does_fire_onJoin_events_for_multiple_Channels() throws Exceptio try (ServerEventsClient client = createServerEventsClient("http://chat.servicestack.net", channels)) { client - .setOnCommand(e -> { - System.out.print("onCommand: " + e); + .setOnJoin(e -> { + System.out.print("onJoin: " + e); - if (e instanceof ServerEventJoin) { - ServerEventJoin joinMsg = (ServerEventJoin)e; - joinMsgs.add(joinMsg); + joinMsgs.add(e); + assertEquals(channels[joinMsgs.size() - 1], e.getChannel()); + assertEquals(client.getConnectionInfo().getDisplayName(), e.getDisplayName()); - assertEquals(channels[joinMsgs.size() - 1], joinMsg.getChannel()); - assertEquals(client.getConnectionInfo().getDisplayName(), joinMsg.getDisplayName()); - - if (joinMsgs.size() == channels.length) - signal.countDown(); - } + if (joinMsgs.size() == channels.length) + signal.countDown(); }) .start(); diff --git a/src/AndroidClient/kotlin/kotlin.iml b/src/AndroidClient/kotlin/kotlin.iml index 2e721932..6ed3a096 100644 --- a/src/AndroidClient/kotlin/kotlin.iml +++ b/src/AndroidClient/kotlin/kotlin.iml @@ -68,14 +68,6 @@ - - - - - - - - @@ -84,6 +76,14 @@ + + + + + + + + diff --git a/src/AndroidClient/techstackskotlin/techstackskotlin.iml b/src/AndroidClient/techstackskotlin/techstackskotlin.iml index e5421280..34e205d7 100644 --- a/src/AndroidClient/techstackskotlin/techstackskotlin.iml +++ b/src/AndroidClient/techstackskotlin/techstackskotlin.iml @@ -67,14 +67,6 @@ - - - - - - - - @@ -83,6 +75,14 @@ + + + + + + + + From 9aea349e9b145a02db3629e1f6386b76e61519da Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Tue, 21 Mar 2017 02:37:41 -0400 Subject: [PATCH 031/211] Support invoking receivers with no arguments --- .../client/sse/ServerEventsClient.java | 18 +++++++++++++----- .../client/TestJavaScriptReceiver.java | 4 ++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index 051f0e12..bbe1b7d0 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -238,11 +238,23 @@ public void execute(ServerEventsClient client, ServerEventMessage msg) { if (!Modifier.isPublic(mi.getModifiers()) || Modifier.isStatic(mi.getModifiers())) continue; Class[] args = mi.getParameterTypes(); - if (args.length != 1) + if (args.length > 1) continue; if ("equals".equals(mi.getName())) continue; + String actionName = mi.getName(); + if (!target.equalsIgnoreCase(actionName) && actionName.startsWith("set")) + actionName = actionName.substring(3); //= "set".length() + + if (args.length == 0){ + if (target.equalsIgnoreCase(actionName)) { + mi.invoke(receiver, null); + return; + } + continue; + } + Class requestType = args[0]; if (target.equals(requestType.getSimpleName()) && @@ -254,10 +266,6 @@ public void execute(ServerEventsClient client, ServerEventMessage msg) { return; } - String actionName = mi.getName(); - if (!target.equalsIgnoreCase(actionName) && actionName.startsWith("set")) - actionName = actionName.substring(3); //= "set".length() - if (target.equalsIgnoreCase(actionName)) { Object request = !Utils.isNullOrEmpty(msg.getJson()) ? JsonUtils.fromJson(msg.getJson(), requestType) diff --git a/src/AndroidClient/client/src/test/java/net/servicestack/client/TestJavaScriptReceiver.java b/src/AndroidClient/client/src/test/java/net/servicestack/client/TestJavaScriptReceiver.java index cc837a8f..dee3701d 100644 --- a/src/AndroidClient/client/src/test/java/net/servicestack/client/TestJavaScriptReceiver.java +++ b/src/AndroidClient/client/src/test/java/net/servicestack/client/TestJavaScriptReceiver.java @@ -31,9 +31,9 @@ public void announce(String message) AnnounceInstance = message; } - public void toggle(String message) + public void toggle() { - ToggleReceived = message; + ToggleReceived = ""; ToggleRequestReceived = super.getRequest(); } From d642cb23fdf62fbe3aa13caa9312c3162fbae629 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Tue, 21 Mar 2017 02:53:50 -0400 Subject: [PATCH 032/211] Add ActionVoid/onReconnect callback to match TypeScript SSE --- .../client/sse/ServerEventJoinCallback.java | 6 ++ .../client/sse/ServerEventLeaveCallback.java | 6 ++ .../client/sse/ServerEventUpdateCallback.java | 5 + .../client/sse/ServerEventsClient.java | 97 +++++++++++++++++-- .../net/servicestack/func/ActionVoid.java | 9 ++ .../client/sse/ServerEventsClient.java | 10 ++ .../net/servicestack/func/ActionVoid.java | 9 ++ 7 files changed, 134 insertions(+), 8 deletions(-) create mode 100644 src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventJoinCallback.java create mode 100644 src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventLeaveCallback.java create mode 100644 src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventUpdateCallback.java create mode 100644 src/AndroidClient/android/src/main/java/net/servicestack/func/ActionVoid.java create mode 100644 src/AndroidClient/client/src/main/java/net/servicestack/func/ActionVoid.java diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventJoinCallback.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventJoinCallback.java new file mode 100644 index 00000000..7568f56e --- /dev/null +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventJoinCallback.java @@ -0,0 +1,6 @@ +package net.servicestack.client.sse; + +public interface ServerEventJoinCallback { + void execute(ServerEventJoin e); +} + diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventLeaveCallback.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventLeaveCallback.java new file mode 100644 index 00000000..07517608 --- /dev/null +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventLeaveCallback.java @@ -0,0 +1,6 @@ +package net.servicestack.client.sse; + +public interface ServerEventLeaveCallback { + void execute(ServerEventLeave e); +} + diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventUpdateCallback.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventUpdateCallback.java new file mode 100644 index 00000000..36f9bdae --- /dev/null +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventUpdateCallback.java @@ -0,0 +1,5 @@ +package net.servicestack.client.sse; + +public interface ServerEventUpdateCallback { + void execute(ServerEventUpdate e); +} diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index b5e3d322..b699bf0b 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -9,6 +9,7 @@ import net.servicestack.client.Log; import net.servicestack.client.Utils; import net.servicestack.func.Action; +import net.servicestack.func.ActionVoid; import net.servicestack.func.Func; import net.servicestack.func.Function; @@ -52,8 +53,12 @@ public class ServerEventsClient implements Closeable { protected ServerEventConnectCallback onConnect; protected ServerEventMessageCallback onMessage; + protected ServerEventJoinCallback onJoin; + protected ServerEventLeaveCallback onLeave; + protected ServerEventUpdateCallback onUpdate; protected ServerEventMessageCallback onCommand; protected ServerEventMessageCallback onHeartbeat; + protected ActionVoid onReconnect; protected ExceptionCallback onException; protected HttpRequestFilter heartbeatRequestFilter; @@ -156,11 +161,31 @@ public ServerEventsClient setOnMessage(ServerEventMessageCallback onMessage) { return this; } + public ServerEventsClient setOnJoin(ServerEventJoinCallback onJoin) { + this.onJoin = onJoin; + return this; + } + + public ServerEventsClient setOnLeave(ServerEventLeaveCallback onLeave) { + this.onLeave = onLeave; + return this; + } + + public ServerEventsClient setOnUpdate(ServerEventUpdateCallback onUpdate) { + this.onUpdate = onUpdate; + return this; + } + public ServerEventsClient setOnCommand(ServerEventMessageCallback onCommand) { this.onCommand = onCommand; return this; } + public ServerEventsClient setOnReconnect(ActionVoid onReconnect) { + this.onReconnect = onReconnect; + return this; + } + public ServerEventsClient setOnException(ExceptionCallback onException) { this.onException = onException; return this; @@ -220,11 +245,23 @@ public void execute(ServerEventsClient client, ServerEventMessage msg) { if (!Modifier.isPublic(mi.getModifiers()) || Modifier.isStatic(mi.getModifiers())) continue; Class[] args = mi.getParameterTypes(); - if (args.length != 1) + if (args.length > 1) continue; if ("equals".equals(mi.getName())) continue; + String actionName = mi.getName(); + if (!target.equalsIgnoreCase(actionName) && actionName.startsWith("set")) + actionName = actionName.substring(3); //= "set".length() + + if (args.length == 0){ + if (target.equalsIgnoreCase(actionName)) { + mi.invoke(receiver, null); + return; + } + continue; + } + Class requestType = args[0]; if (target.equals(requestType.getSimpleName()) && @@ -236,10 +273,6 @@ public void execute(ServerEventsClient client, ServerEventMessage msg) { return; } - String actionName = mi.getName(); - if (!target.equalsIgnoreCase(actionName) && actionName.startsWith("set")) - actionName = actionName.substring(3); //= "set".length() - if (target.equalsIgnoreCase(actionName)) { Object request = !Utils.isNullOrEmpty(msg.getJson()) ? JsonUtils.fromJson(msg.getJson(), requestType) @@ -317,6 +350,9 @@ public synchronized void restart() { onExceptionReceived(e); } + if (onReconnect != null){ + onReconnect.apply(); + } } catch (Exception ex){ Log.e("[SSE-CLIENT] Error whilst restarting: " + ex.getMessage(), ex); ex.printStackTrace(); @@ -377,6 +413,42 @@ private synchronized void internalStop() { stopBackgroundThread(); } + private void onJoinReceived(ServerEventJoin e) { + if (Log.isDebugEnabled()) + Log.d("[SSE-CLIENT] OnJoinReceived: (" + + e.getClass().getSimpleName() + ") #" + + e.getEventId() + " on #" + + getConnectionDisplayName() + " (" + + Utils.join(channels, ",") + ")"); + + if (onJoin != null) + onJoin.execute(e); + } + + private void onLeaveReceived(ServerEventLeave e) { + if (Log.isDebugEnabled()) + Log.d("[SSE-CLIENT] OnLeaveReceived: (" + + e.getClass().getSimpleName() + ") #" + + e.getEventId() + " on #" + + getConnectionDisplayName() + " (" + + Utils.join(channels, ",") + ")"); + + if (onLeave != null) + onLeave.execute(e); + } + + private void onUpdateReceived(ServerEventUpdate e) { + if (Log.isDebugEnabled()) + Log.d("[SSE-CLIENT] OnUpdateReceived: (" + + e.getClass().getSimpleName() + ") #" + + e.getEventId() + " on #" + + getConnectionDisplayName() + " (" + + Utils.join(channels, ",") + ")"); + + if (onUpdate != null) + onUpdate.execute(e); + } + private void onCommandReceived(ServerEventMessage e) { if (Log.isDebugEnabled()) Log.d("[SSE-CLIENT] OnCommandReceived: (" @@ -570,15 +642,24 @@ protected void processOnConnectMessage(ServerEventMessage e) { } protected void processOnJoinMessage(ServerEventMessage e) { - onCommandReceived(new ServerEventJoin().populate(e, JsonUtils.toJsonObject(e.getJson()))); + ServerEventJoin m = new ServerEventJoin(); + m.populate(e, JsonUtils.toJsonObject(e.getJson())); + onJoinReceived(m); + onCommandReceived(m); } protected void processOnLeaveMessage(ServerEventMessage e) { - onCommandReceived(new ServerEventLeave().populate(e, JsonUtils.toJsonObject(e.getJson()))); + ServerEventLeave m = new ServerEventLeave(); + m.populate(e, JsonUtils.toJsonObject(e.getJson())); + onLeaveReceived(m); + onCommandReceived(m); } protected void processOnUpdateMessage(ServerEventMessage e) { - onCommandReceived(new ServerEventUpdate().populate(e, JsonUtils.toJsonObject(e.getJson()))); + ServerEventUpdate m = new ServerEventUpdate(); + m.populate(e, JsonUtils.toJsonObject(e.getJson())); + onUpdateReceived(m); + onCommandReceived(m); } protected void processOnHeartbeatMessage(ServerEventMessage e) { diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/func/ActionVoid.java b/src/AndroidClient/android/src/main/java/net/servicestack/func/ActionVoid.java new file mode 100644 index 00000000..62676914 --- /dev/null +++ b/src/AndroidClient/android/src/main/java/net/servicestack/func/ActionVoid.java @@ -0,0 +1,9 @@ +package net.servicestack.func; + +/** + * Created by mythz on 3/21/2017. + */ + +public interface ActionVoid { + public void apply(); +} diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index bbe1b7d0..b699bf0b 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -9,6 +9,7 @@ import net.servicestack.client.Log; import net.servicestack.client.Utils; import net.servicestack.func.Action; +import net.servicestack.func.ActionVoid; import net.servicestack.func.Func; import net.servicestack.func.Function; @@ -57,6 +58,7 @@ public class ServerEventsClient implements Closeable { protected ServerEventUpdateCallback onUpdate; protected ServerEventMessageCallback onCommand; protected ServerEventMessageCallback onHeartbeat; + protected ActionVoid onReconnect; protected ExceptionCallback onException; protected HttpRequestFilter heartbeatRequestFilter; @@ -179,6 +181,11 @@ public ServerEventsClient setOnCommand(ServerEventMessageCallback onCommand) { return this; } + public ServerEventsClient setOnReconnect(ActionVoid onReconnect) { + this.onReconnect = onReconnect; + return this; + } + public ServerEventsClient setOnException(ExceptionCallback onException) { this.onException = onException; return this; @@ -343,6 +350,9 @@ public synchronized void restart() { onExceptionReceived(e); } + if (onReconnect != null){ + onReconnect.apply(); + } } catch (Exception ex){ Log.e("[SSE-CLIENT] Error whilst restarting: " + ex.getMessage(), ex); ex.printStackTrace(); diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/func/ActionVoid.java b/src/AndroidClient/client/src/main/java/net/servicestack/func/ActionVoid.java new file mode 100644 index 00000000..62676914 --- /dev/null +++ b/src/AndroidClient/client/src/main/java/net/servicestack/func/ActionVoid.java @@ -0,0 +1,9 @@ +package net.servicestack.func; + +/** + * Created by mythz on 3/21/2017. + */ + +public interface ActionVoid { + public void apply(); +} From 814bba0f00d3438986946b1403164ca205031e7f Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Tue, 21 Mar 2017 15:37:52 -0400 Subject: [PATCH 033/211] Add example of accessing string message from handler --- .../servicestack/client/ServerEventClientTests.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java index e43997bc..00b2db51 100644 --- a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java +++ b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java @@ -363,8 +363,13 @@ public void test_Does_reconnect_on_lost_connection() throws Exception { public void test_Does_send_message_to_Handler() throws Exception { List chatMsgs = new ArrayList<>(); + List paintMsgs = new ArrayList<>(); try(ServerEventsClient client1 = createServerEventsClient("http://chat.servicestack.net") + .registerHandler("paint", (client, e) -> { + String color = JsonUtils.fromJson(e.getJson(), String.class); + paintMsgs.add(color); + }) .registerHandler("chat", (client, e) -> { ChatMessage chatMsg = JsonUtils.fromJson(e.getJson(), ChatMessage.class); chatMsgs.add(chatMsg); @@ -389,6 +394,14 @@ public void test_Does_send_message_to_Handler() throws Exception { chatMsg = Func.last(chatMsgs); assertEquals("msg2", chatMsg.getMessage()); + + postRaw(client1, "cmd.paint$#town", "red"); + + while (paintMsgs.size() < 1){ + Thread.sleep(100); + } + + assertEquals("red", paintMsgs.get(0)); } } From 29c9db57bc6888b4f538c97aed8763a9f9621c39 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Tue, 21 Mar 2017 15:38:30 -0400 Subject: [PATCH 034/211] Add Func.forEach alias for Func.each --- .../src/main/java/net/servicestack/func/Func.java | 9 +++++++++ .../client/src/main/java/net/servicestack/func/Func.java | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/func/Func.java b/src/AndroidClient/android/src/main/java/net/servicestack/func/Func.java index df72f0e4..e214a894 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/func/Func.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/func/Func.java @@ -9,6 +9,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -170,6 +171,14 @@ public static void each(Iterable xs, Action f) { } } + public static void forEach(T[] xs, Action f) { + each(toList(xs), f); + } + + public static void forEach(Iterable xs, Action f){ + each(xs, f); + } + public static ArrayList filter(T[] xs, Predicate predicate) { return filter(toList(xs), predicate); } diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/func/Func.java b/src/AndroidClient/client/src/main/java/net/servicestack/func/Func.java index df72f0e4..e214a894 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/func/Func.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/func/Func.java @@ -9,6 +9,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -170,6 +171,14 @@ public static void each(Iterable xs, Action f) { } } + public static void forEach(T[] xs, Action f) { + each(toList(xs), f); + } + + public static void forEach(Iterable xs, Action f){ + each(xs, f); + } + public static ArrayList filter(T[] xs, Predicate predicate) { return filter(toList(xs), predicate); } From 0c12d7f8db405586a2e8d27af72e6eff46b0c3ec Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Tue, 21 Mar 2017 16:12:24 -0400 Subject: [PATCH 035/211] Bump to v1.0.31 --- src/AndroidClient/android/build.gradle | 2 +- src/AndroidClient/client/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AndroidClient/android/build.gradle b/src/AndroidClient/android/build.gradle index e91a5df8..053978ab 100644 --- a/src/AndroidClient/android/build.gradle +++ b/src/AndroidClient/android/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.library' apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' -version = "1.0.30" +version = "1.0.31" dependencies { compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/src/AndroidClient/client/build.gradle b/src/AndroidClient/client/build.gradle index 9eb69a2e..8518b7bd 100644 --- a/src/AndroidClient/client/build.gradle +++ b/src/AndroidClient/client/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' -version = "1.0.30" +version = "1.0.31" dependencies { compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' From 64c6d5c84af98360d7bca480640b38f4fb6c8607 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Wed, 5 Jul 2017 12:21:28 -0400 Subject: [PATCH 036/211] Change heartbeat Timer to use newer ScheduledThreadPoolExecutor --- .../client/sse/ServerEventsClient.java | 23 ++++++++++++------- .../client/sse/ServerEventsClient.java | 23 ++++++++++++------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index b699bf0b..0fa18dd0 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -29,8 +29,8 @@ import java.util.Locale; import java.util.Map; import java.util.Random; -import java.util.Timer; -import java.util.TimerTask; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -409,6 +409,14 @@ private synchronized void internalStop() { } catch (Exception ignore) {} } + if (heartbeatTimer != null) + { + try { + heartbeatTimer.shutdown(); + } catch (Exception ignore) {} + heartbeatTimer = null; + } + connectionInfo = null; stopBackgroundThread(); } @@ -553,7 +561,7 @@ public synchronized void raiseEvent(String eventName, ServerEventMessage message } } - Timer heratbeatTimer; + ScheduledThreadPoolExecutor heartbeatTimer; private void startNewHeartbeat() { if (connectionInfo == null || connectionInfo.getHeartbeatUrl() == null) @@ -562,16 +570,15 @@ private void startNewHeartbeat() { if (stopped.get()) return; - if (heratbeatTimer == null) - heratbeatTimer = new Timer("ServerEventsClient Heartbeat"); + if (heartbeatTimer == null) + heartbeatTimer = new ScheduledThreadPoolExecutor(1); - //reschedule timer on every heartbeat - heratbeatTimer.schedule(new TimerTask() { + heartbeatTimer.schedule(new Runnable() { @Override public void run() { Heartbeat(); } - }, connectionInfo.getHeartbeatIntervalMs(), Integer.MAX_VALUE); + }, connectionInfo.getHeartbeatIntervalMs(), TimeUnit.MILLISECONDS); } public void Heartbeat(){ diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index b699bf0b..0fa18dd0 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -29,8 +29,8 @@ import java.util.Locale; import java.util.Map; import java.util.Random; -import java.util.Timer; -import java.util.TimerTask; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -409,6 +409,14 @@ private synchronized void internalStop() { } catch (Exception ignore) {} } + if (heartbeatTimer != null) + { + try { + heartbeatTimer.shutdown(); + } catch (Exception ignore) {} + heartbeatTimer = null; + } + connectionInfo = null; stopBackgroundThread(); } @@ -553,7 +561,7 @@ public synchronized void raiseEvent(String eventName, ServerEventMessage message } } - Timer heratbeatTimer; + ScheduledThreadPoolExecutor heartbeatTimer; private void startNewHeartbeat() { if (connectionInfo == null || connectionInfo.getHeartbeatUrl() == null) @@ -562,16 +570,15 @@ private void startNewHeartbeat() { if (stopped.get()) return; - if (heratbeatTimer == null) - heratbeatTimer = new Timer("ServerEventsClient Heartbeat"); + if (heartbeatTimer == null) + heartbeatTimer = new ScheduledThreadPoolExecutor(1); - //reschedule timer on every heartbeat - heratbeatTimer.schedule(new TimerTask() { + heartbeatTimer.schedule(new Runnable() { @Override public void run() { Heartbeat(); } - }, connectionInfo.getHeartbeatIntervalMs(), Integer.MAX_VALUE); + }, connectionInfo.getHeartbeatIntervalMs(), TimeUnit.MILLISECONDS); } public void Heartbeat(){ From d68aee6b2b5a8f5bedf9e64b5d6a51f8adbf9fbd Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Wed, 5 Jul 2017 12:24:47 -0400 Subject: [PATCH 037/211] bump version to 1.0.32 --- src/AndroidClient/android/build.gradle | 2 +- src/AndroidClient/client/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AndroidClient/android/build.gradle b/src/AndroidClient/android/build.gradle index 053978ab..ac5e7468 100644 --- a/src/AndroidClient/android/build.gradle +++ b/src/AndroidClient/android/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.library' apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' -version = "1.0.31" +version = "1.0.32" dependencies { compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/src/AndroidClient/client/build.gradle b/src/AndroidClient/client/build.gradle index 8518b7bd..3919537e 100644 --- a/src/AndroidClient/client/build.gradle +++ b/src/AndroidClient/client/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' -version = "1.0.31" +version = "1.0.32" dependencies { compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' From 98c157ef3de34748556805ac501c025fcd1a2d51 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Thu, 6 Jul 2017 20:18:21 -0400 Subject: [PATCH 038/211] Add integration test to leave ServerEventsClient running for 1 hour --- .../servicestack/client/ServerEventClientTests.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java index 00b2db51..b6dd0f24 100644 --- a/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java +++ b/src/AndroidClient/client/src/test/java/net/servicestack/client/ServerEventClientTests.java @@ -24,6 +24,7 @@ import static chat.chatdtos.PostChatToChannel; import static chat.chatdtos.ResetServerEvents; import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertFalse; /** * Created by mythz on 2/10/2017. @@ -39,6 +40,18 @@ public ServerEventsClient createServerEventsClient(String baseUrl, String... cha return new ServerEventsClient(baseUrl, channels); } + public void renameto_test_leave_running() throws InterruptedException { + final CountDownLatch signal = new CountDownLatch(1); + + try (ServerEventsClient client = createServerEventsClient("http://chat.servicestack.net", "home") + .setOnConnect(e -> { + System.out.print("onConnect: " + e); + }).start()) + { + assertFalse(signal.await(60, TimeUnit.MINUTES)); + } + } + public void test_Can_connect_to_ServerEventsStream() throws Exception { final CountDownLatch signal = new CountDownLatch(1); From c95a6772afe397c4dba8990a2499103334dba687 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 7 Jul 2017 03:26:34 -0400 Subject: [PATCH 039/211] Change to use scheduleWithFixedDelay --- .../net/servicestack/client/sse/ServerEventsClient.java | 6 ++---- .../net/servicestack/client/sse/ServerEventsClient.java | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index 0fa18dd0..ca57c030 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -573,12 +573,12 @@ private void startNewHeartbeat() { if (heartbeatTimer == null) heartbeatTimer = new ScheduledThreadPoolExecutor(1); - heartbeatTimer.schedule(new Runnable() { + heartbeatTimer.scheduleWithFixedDelay(new Runnable() { @Override public void run() { Heartbeat(); } - }, connectionInfo.getHeartbeatIntervalMs(), TimeUnit.MILLISECONDS); + }, connectionInfo.getHeartbeatIntervalMs(), connectionInfo.getHeartbeatIntervalMs(), TimeUnit.MILLISECONDS); } public void Heartbeat(){ @@ -621,8 +621,6 @@ public void Heartbeat(){ if (Log.isDebugEnabled()) Log.d("[SSE-CLIENT] Heartbeat sent to: " + heartbeatUrl); - startNewHeartbeat(); - } catch (Exception e) { if (Log.isDebugEnabled()) Log.d("[SSE-CLIENT] Error from Heartbeat: " + e); diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java index 0fa18dd0..ca57c030 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/sse/ServerEventsClient.java @@ -573,12 +573,12 @@ private void startNewHeartbeat() { if (heartbeatTimer == null) heartbeatTimer = new ScheduledThreadPoolExecutor(1); - heartbeatTimer.schedule(new Runnable() { + heartbeatTimer.scheduleWithFixedDelay(new Runnable() { @Override public void run() { Heartbeat(); } - }, connectionInfo.getHeartbeatIntervalMs(), TimeUnit.MILLISECONDS); + }, connectionInfo.getHeartbeatIntervalMs(), connectionInfo.getHeartbeatIntervalMs(), TimeUnit.MILLISECONDS); } public void Heartbeat(){ @@ -621,8 +621,6 @@ public void Heartbeat(){ if (Log.isDebugEnabled()) Log.d("[SSE-CLIENT] Heartbeat sent to: " + heartbeatUrl); - startNewHeartbeat(); - } catch (Exception e) { if (Log.isDebugEnabled()) Log.d("[SSE-CLIENT] Error from Heartbeat: " + e); From 45103f20a681f3387d9d30bf709240ea9046dd0b Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 7 Jul 2017 03:31:56 -0400 Subject: [PATCH 040/211] bump to v1.0.33 --- src/AndroidClient/android/build.gradle | 2 +- src/AndroidClient/client/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AndroidClient/android/build.gradle b/src/AndroidClient/android/build.gradle index ac5e7468..4d41d5a6 100644 --- a/src/AndroidClient/android/build.gradle +++ b/src/AndroidClient/android/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.library' apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' -version = "1.0.32" +version = "1.0.33" dependencies { compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' diff --git a/src/AndroidClient/client/build.gradle b/src/AndroidClient/client/build.gradle index 3919537e..03c59045 100644 --- a/src/AndroidClient/client/build.gradle +++ b/src/AndroidClient/client/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' -version = "1.0.32" +version = "1.0.33" dependencies { compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' From 07ca610654f5f1d50065f30e340623a33ee9de05 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Tue, 16 Jan 2018 00:33:04 -0500 Subject: [PATCH 041/211] Fix duplicate slashes in path --- .../idea/UpdateServiceStackUtils.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/UpdateServiceStackUtils.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/UpdateServiceStackUtils.java index c10ef5e2..3ac453d8 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/UpdateServiceStackUtils.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/UpdateServiceStackUtils.java @@ -67,9 +67,9 @@ public static void updateServiceStackReference(PsiFile psiFile) { String existingPath = builder.getPath(); if(existingPath == null || existingPath.equals("/")) { - builder.setPath("/" + nativeTypesHandler.getRelativeTypesUrl()); + builder.setPath(combinePath("", nativeTypesHandler.getRelativeTypesUrl())); } else { - builder.setPath(existingPath + "/" + nativeTypesHandler.getRelativeTypesUrl()); + builder.setPath(combinePath(existingPath, nativeTypesHandler.getRelativeTypesUrl())); } Map options = new HashMap(); @@ -134,6 +134,18 @@ public static void updateServiceStackReference(PsiFile psiFile) { } } + public static String combinePath(String path, String segment) { + if (path == null || path.isEmpty()) { + return "/" + segment; + } + + if (path.charAt(path.length() - 1) == '/') { + return path + segment; + } + + return path + "/" + segment; + } + public static boolean containsOptionsHeader(PsiFile psiJavaFile) { Document dtoDocument = FileDocumentManager.getInstance().getDocument(psiJavaFile.getVirtualFile()); if(dtoDocument == null) { From f8ee1532024b0dc103d57b14c4605395ddd19a86 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 6 Apr 2018 18:24:07 -0400 Subject: [PATCH 042/211] Add missing IMeta and fix isKotlinClass --- .../android/src/main/java/net/servicestack/client/IMeta.java | 4 ++++ .../android/src/main/java/net/servicestack/client/Utils.java | 4 +++- .../client/src/main/java/net/servicestack/client/IMeta.java | 4 ++++ .../client/src/main/java/net/servicestack/client/Utils.java | 4 +++- 4 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 src/AndroidClient/android/src/main/java/net/servicestack/client/IMeta.java create mode 100644 src/AndroidClient/client/src/main/java/net/servicestack/client/IMeta.java diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/IMeta.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/IMeta.java new file mode 100644 index 00000000..56c37afd --- /dev/null +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/IMeta.java @@ -0,0 +1,4 @@ +package net.servicestack.client; + +public interface IMeta { +} diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/Utils.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/Utils.java index 7f2798eb..2b21e210 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/Utils.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/Utils.java @@ -62,11 +62,13 @@ public static Double tryParseDouble(String str) { } static final String KotlinAnnotationClass = "kotlin.jvm.internal.KotlinClass"; + static final String KotliMetadataClass = "kotlin.Metadata"; public static boolean isKotlinClass(Class type) { for (Annotation attr : type.getAnnotations()){ - if (KotlinAnnotationClass.equals(attr.annotationType().getName())) + String annotationName = attr.annotationType().getName(); + if (KotlinAnnotationClass.equals(annotationName) || KotliMetadataClass.equals(annotationName)) return true; } return false; diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/IMeta.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/IMeta.java new file mode 100644 index 00000000..56c37afd --- /dev/null +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/IMeta.java @@ -0,0 +1,4 @@ +package net.servicestack.client; + +public interface IMeta { +} diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/Utils.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/Utils.java index 7f2798eb..2b21e210 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/Utils.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/Utils.java @@ -62,11 +62,13 @@ public static Double tryParseDouble(String str) { } static final String KotlinAnnotationClass = "kotlin.jvm.internal.KotlinClass"; + static final String KotliMetadataClass = "kotlin.Metadata"; public static boolean isKotlinClass(Class type) { for (Annotation attr : type.getAnnotations()){ - if (KotlinAnnotationClass.equals(attr.annotationType().getName())) + String annotationName = attr.annotationType().getName(); + if (KotlinAnnotationClass.equals(annotationName) || KotliMetadataClass.equals(annotationName)) return true; } return false; From b8c1af6a60efa718bf2becbcb7a05f191fb88f0e Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sun, 15 Apr 2018 01:24:05 -0400 Subject: [PATCH 043/211] Upgrade to latest Android version --- .../.idea/caches/build_file_checksums.ser | Bin 0 -> 845 bytes .../.idea/codeStyles/Project.xml | 29 + src/AndroidClient/.idea/kotlinc.xml | 7 + src/AndroidClient/.idea/misc.xml | 12 +- src/AndroidClient/AndroidClient.iml | 7 +- src/AndroidClient/android/android.iml | 89 +- src/AndroidClient/android/build.gradle | 2 +- src/AndroidClient/androidchat/androidchat.iml | 165 +- src/AndroidClient/androidchat/build.gradle | 23 +- .../androidchat/google-services.json | 52 + src/AndroidClient/app/app.iml | 114 +- src/AndroidClient/app/build.gradle | 8 +- src/AndroidClient/build.gradle | 13 +- src/AndroidClient/client/client.iml | 12 +- src/AndroidClient/client/pom.xml | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 4 +- src/AndroidClient/kotlin/build.gradle | 10 +- src/AndroidClient/kotlin/kotlin.iml | 129 +- .../projectFilesBackup1/.idea/workspace.xml | 8391 +++++++++++++++++ src/AndroidClient/techstacks/build.gradle | 8 +- src/AndroidClient/techstacks/techstacks.iml | 126 +- .../techstackskotlin/build.gradle | 12 +- .../techstackskotlin/techstackskotlin.iml | 156 +- src/ServiceStackIDEA/.idea/misc.xml | 12 +- src/ServiceStackIDEA/.idea/workspace.xml | 914 +- 25 files changed, 9268 insertions(+), 1029 deletions(-) create mode 100644 src/AndroidClient/.idea/caches/build_file_checksums.ser create mode 100644 src/AndroidClient/.idea/codeStyles/Project.xml create mode 100644 src/AndroidClient/.idea/kotlinc.xml create mode 100644 src/AndroidClient/androidchat/google-services.json create mode 100644 src/AndroidClient/projectFilesBackup1/.idea/workspace.xml diff --git a/src/AndroidClient/.idea/caches/build_file_checksums.ser b/src/AndroidClient/.idea/caches/build_file_checksums.ser new file mode 100644 index 0000000000000000000000000000000000000000..87e92b8359278754b9ee56b85b872a830e71459a GIT binary patch literal 845 zcmZ4UmVvdnh`~NNKUXg?FQq6yGexf?KR>5fFEb@IQ7^qHF(oHeub?PDD>b=9F91S2 zm1gFoxMk*~I%lLNXBU^|7Q2L-Ts|(GuF1r}G+JrGl1?A1j*@vHTg8MHrxq2*LCjdzm{ZMHa@W|XA%>_-WMaB@y& zY96kTPCwymxw4|{t(wdx!?~{7YC!dPJuuNEsc4SM9`h$Xtfj)dhfbF;2;vD*HH-iH Sq190>l@8HQdXC+DS^)r&Brf{^ literal 0 HcmV?d00001 diff --git a/src/AndroidClient/.idea/codeStyles/Project.xml b/src/AndroidClient/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..30aa626c --- /dev/null +++ b/src/AndroidClient/.idea/codeStyles/Project.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AndroidClient/.idea/kotlinc.xml b/src/AndroidClient/.idea/kotlinc.xml new file mode 100644 index 00000000..1c24f9a8 --- /dev/null +++ b/src/AndroidClient/.idea/kotlinc.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/src/AndroidClient/.idea/misc.xml b/src/AndroidClient/.idea/misc.xml index fbb68289..ea250257 100644 --- a/src/AndroidClient/.idea/misc.xml +++ b/src/AndroidClient/.idea/misc.xml @@ -27,17 +27,7 @@ - - - - - - - - - - - + diff --git a/src/AndroidClient/AndroidClient.iml b/src/AndroidClient/AndroidClient.iml index 036b2614..fa760751 100644 --- a/src/AndroidClient/AndroidClient.iml +++ b/src/AndroidClient/AndroidClient.iml @@ -1,5 +1,5 @@ - + @@ -13,8 +13,7 @@ - + - - + \ No newline at end of file diff --git a/src/AndroidClient/android/android.iml b/src/AndroidClient/android/android.iml index 2e94d658..80e6e50b 100644 --- a/src/AndroidClient/android/android.iml +++ b/src/AndroidClient/android/android.iml @@ -1,5 +1,5 @@ - + @@ -9,7 +9,6 @@ - + + - + - + - @@ -56,78 +55,82 @@ - + + + + + + + - - - - - - - - - - + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AndroidClient/android/build.gradle b/src/AndroidClient/android/build.gradle index 4d41d5a6..8b234888 100644 --- a/src/AndroidClient/android/build.gradle +++ b/src/AndroidClient/android/build.gradle @@ -16,7 +16,7 @@ dependencies { android { compileSdkVersion 25 - buildToolsVersion "25.0.2" + buildToolsVersion '27.0.3' defaultConfig { minSdkVersion 15 diff --git a/src/AndroidClient/androidchat/androidchat.iml b/src/AndroidClient/androidchat/androidchat.iml index fdcf27bd..6b81caa1 100644 --- a/src/AndroidClient/androidchat/androidchat.iml +++ b/src/AndroidClient/androidchat/androidchat.iml @@ -9,7 +9,6 @@ - + + - + - + - @@ -56,15 +55,20 @@ - + + + + + + + - @@ -72,7 +76,6 @@ - @@ -80,99 +83,83 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + - + + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AndroidClient/androidchat/build.gradle b/src/AndroidClient/androidchat/build.gradle index c7762f50..7546cc22 100644 --- a/src/AndroidClient/androidchat/build.gradle +++ b/src/AndroidClient/androidchat/build.gradle @@ -1,3 +1,6 @@ +apply plugin: 'com.android.application' +apply plugin: 'io.fabric' + buildscript { repositories { maven { url 'https://maven.fabric.io/public' } @@ -9,31 +12,25 @@ buildscript { // We recommend changing it to the latest version from our changelog: // https://docs.fabric.io/android/changelog.html#fabric-gradle-plugin - classpath 'io.fabric.tools:gradle:1.+' + classpath 'io.fabric.tools:gradle:1.25.2' } } -apply plugin: 'com.android.application' -apply plugin: 'io.fabric' - repositories { maven { url 'https://maven.fabric.io/public' } } android { - compileSdkVersion 25 - buildToolsVersion "25.0.2" + compileSdkVersion 27 + buildToolsVersion '27.0.3' defaultConfig { applicationId "servicestack.net.androidchat" minSdkVersion 21 - targetSdkVersion 25 + targetSdkVersion 27 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - jackOptions { - enabled true - } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -53,10 +50,10 @@ dependencies { exclude group: 'com.android.support', module: 'support-annotations' }) compile project(':android') - compile 'com.android.support:appcompat-v7:25.2.0' - compile 'com.android.support:design:25.2.0' + compile 'com.android.support:appcompat-v7:27.1.1' + compile 'com.android.support:design:27.1.1' compile 'net.servicestack:android:1.0.27' - compile 'com.facebook.android:facebook-android-sdk:[4,5)' + compile 'com.facebook.android:facebook-android-sdk:4.31.0' compile('com.twitter.sdk.android:twitter:2.3.1@aar') { transitive = true; } diff --git a/src/AndroidClient/androidchat/google-services.json b/src/AndroidClient/androidchat/google-services.json new file mode 100644 index 00000000..c65047c4 --- /dev/null +++ b/src/AndroidClient/androidchat/google-services.json @@ -0,0 +1,52 @@ +{ + "project_info": { + "project_number": "1052104404413", + "project_id": "chat-162801" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:1052104404413:android:488b76c4867da4bf", + "android_client_info": { + "package_name": "servicestack.net.androidchat" + } + }, + "oauth_client": [ + { + "client_id": "1052104404413-9nnchqdtv3ahs7r6eti9eet2rff7pr67.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "servicestack.net.androidchat", + "certificate_hash": "35b494838697a46d5c52e5a5436d29d8278f0c01" + } + }, + { + "client_id": "1052104404413-9u4aaoc3hnh01uhmhb38f29chl4i492g.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "1052104404413-ltjkinrgo98st0393ogjcc39va25ll0p.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCgPtwIjcmAcJVJxTqUZbF8bYeqbhXxv0g" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 1 + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/src/AndroidClient/app/app.iml b/src/AndroidClient/app/app.iml index b591e10f..2ac0e99b 100644 --- a/src/AndroidClient/app/app.iml +++ b/src/AndroidClient/app/app.iml @@ -1,5 +1,5 @@ - + @@ -9,7 +9,6 @@ + + + + + + + + + - + + - + - + - @@ -55,16 +76,21 @@ - + + + + + + + - @@ -72,7 +98,6 @@ - @@ -80,49 +105,60 @@ - + + + - - - - + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AndroidClient/app/build.gradle b/src/AndroidClient/app/build.gradle index ca16adc9..559e6025 100644 --- a/src/AndroidClient/app/build.gradle +++ b/src/AndroidClient/app/build.gradle @@ -2,13 +2,13 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' android { - compileSdkVersion 23 - buildToolsVersion "21.1.2" + compileSdkVersion 27 + buildToolsVersion '27.0.3' defaultConfig { applicationId "servicestack.net.androidclient" minSdkVersion 16 - targetSdkVersion 23 + targetSdkVersion 27 versionCode 1 versionName "1.0" } @@ -25,7 +25,7 @@ android { dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') - compile 'com.android.support:appcompat-v7:23.1.1' + compile 'com.android.support:appcompat-v7:27.1.1' compile project(':android') compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" } diff --git a/src/AndroidClient/build.gradle b/src/AndroidClient/build.gradle index a38ef103..487b9174 100644 --- a/src/AndroidClient/build.gradle +++ b/src/AndroidClient/build.gradle @@ -1,12 +1,17 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.0.4' + ext.kotlin_version = '1.2.31' repositories { jcenter() + maven { + url 'https://maven.google.com/' + name 'Google' + } + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' + classpath 'com.android.tools.build:gradle:3.1.1' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" @@ -18,5 +23,9 @@ buildscript { allprojects { repositories { jcenter() + maven { + url 'https://maven.google.com/' + name 'Google' + } } } diff --git a/src/AndroidClient/client/client.iml b/src/AndroidClient/client/client.iml index 73d50594..a4d26341 100644 --- a/src/AndroidClient/client/client.iml +++ b/src/AndroidClient/client/client.iml @@ -1,5 +1,5 @@ - + @@ -13,9 +13,9 @@ - - - + + + @@ -27,7 +27,9 @@ - + + + diff --git a/src/AndroidClient/client/pom.xml b/src/AndroidClient/client/pom.xml index 3ddc7da8..dfefbf28 100644 --- a/src/AndroidClient/client/pom.xml +++ b/src/AndroidClient/client/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.servicestack client - 1.0.30 + 1.0.33 ServiceStack.Client A client library to call your ServiceStack webservices. https://github.com/ServiceStack/ServiceStack.Java diff --git a/src/AndroidClient/gradle/wrapper/gradle-wrapper.properties b/src/AndroidClient/gradle/wrapper/gradle-wrapper.properties index 2799ab94..25549b90 100644 --- a/src/AndroidClient/gradle/wrapper/gradle-wrapper.properties +++ b/src/AndroidClient/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Sep 22 15:14:45 EDT 2016 +#Fri Apr 06 08:00:55 EDT 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/src/AndroidClient/kotlin/build.gradle b/src/AndroidClient/kotlin/build.gradle index 8344100a..7f462225 100644 --- a/src/AndroidClient/kotlin/build.gradle +++ b/src/AndroidClient/kotlin/build.gradle @@ -2,12 +2,12 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - compileSdkVersion 24 - buildToolsVersion "23.0.2" + compileSdkVersion 27 + buildToolsVersion '27.0.3' defaultConfig { minSdkVersion 16 - targetSdkVersion 24 + targetSdkVersion 27 versionCode 1 versionName "1.0" } @@ -25,12 +25,12 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' - compile 'com.android.support:appcompat-v7:24.2.1' + compile 'com.android.support:appcompat-v7:27.1.1' compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile project(':android') } buildscript { - ext.kotlin_version = '1.0.4' + ext.kotlin_version = '1.2.31' repositories { mavenCentral() } diff --git a/src/AndroidClient/kotlin/kotlin.iml b/src/AndroidClient/kotlin/kotlin.iml index 6ed3a096..01766e75 100644 --- a/src/AndroidClient/kotlin/kotlin.iml +++ b/src/AndroidClient/kotlin/kotlin.iml @@ -1,5 +1,5 @@ - + @@ -9,7 +9,6 @@ + + + + + + + + - + + - + - + - + + + + + + + - @@ -65,7 +92,6 @@ - @@ -73,7 +99,6 @@ - @@ -81,70 +106,64 @@ - + + + - - - - - - - - - - + - + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AndroidClient/projectFilesBackup1/.idea/workspace.xml b/src/AndroidClient/projectFilesBackup1/.idea/workspace.xml new file mode 100644 index 00000000..de4cf109 --- /dev/null +++ b/src/AndroidClient/projectFilesBackup1/.idea/workspace.xml @@ -0,0 +1,8391 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1487136572108 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + file://$PROJECT_DIR$/android/src/main/java/net/servicestack/client/JsonServiceClient.java + 400 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AndroidClient/techstacks/build.gradle b/src/AndroidClient/techstacks/build.gradle index 1e7241ea..532c8110 100644 --- a/src/AndroidClient/techstacks/build.gradle +++ b/src/AndroidClient/techstacks/build.gradle @@ -2,13 +2,13 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' android { - compileSdkVersion 24 - buildToolsVersion "23.0.2" + compileSdkVersion 27 + buildToolsVersion '27.0.3' defaultConfig { applicationId "servicestack.net.techstacks" minSdkVersion 19 - targetSdkVersion 24 + targetSdkVersion 27 versionCode 1 versionName "1.0" } @@ -28,7 +28,7 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:24.2.1' + compile 'com.android.support:appcompat-v7:27.1.1' compile project(':android') compile 'com.squareup.picasso:picasso:2.5.2' } diff --git a/src/AndroidClient/techstacks/techstacks.iml b/src/AndroidClient/techstacks/techstacks.iml index 46c73ede..9b6c1170 100644 --- a/src/AndroidClient/techstacks/techstacks.iml +++ b/src/AndroidClient/techstacks/techstacks.iml @@ -1,5 +1,5 @@ - + @@ -9,7 +9,6 @@ + + + + + + + + + - + + - + - + - + + + + + + + - @@ -64,78 +91,59 @@ - - - - - - - - - - + + + + + + + + - - - - - - - - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AndroidClient/techstackskotlin/build.gradle b/src/AndroidClient/techstackskotlin/build.gradle index 25207ed2..f8ab0b02 100644 --- a/src/AndroidClient/techstackskotlin/build.gradle +++ b/src/AndroidClient/techstackskotlin/build.gradle @@ -2,13 +2,13 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' android { - compileSdkVersion 24 - buildToolsVersion "23.0.2" + compileSdkVersion 27 + buildToolsVersion '27.0.3' defaultConfig { applicationId "test.servicestack.net.techstackskotlin" minSdkVersion 16 - targetSdkVersion 24 + targetSdkVersion 27 versionCode 1 versionName "1.0" } @@ -26,14 +26,14 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' - compile 'com.android.support:appcompat-v7:24.2.1' - compile 'com.android.support:design:24.2.1' + compile 'com.android.support:appcompat-v7:27.1.1' + compile 'com.android.support:design:27.1.1' compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile project(':android') compile 'com.squareup.picasso:picasso:2.5.2' } buildscript { - ext.kotlin_version = '1.0.4' + ext.kotlin_version = '1.2.31' repositories { mavenCentral() } diff --git a/src/AndroidClient/techstackskotlin/techstackskotlin.iml b/src/AndroidClient/techstackskotlin/techstackskotlin.iml index 34e205d7..9a112b59 100644 --- a/src/AndroidClient/techstackskotlin/techstackskotlin.iml +++ b/src/AndroidClient/techstackskotlin/techstackskotlin.iml @@ -1,5 +1,5 @@ - + @@ -9,7 +9,6 @@ + + + + + + + + + - + + - + - + - @@ -55,93 +76,98 @@ - + + + + + + + - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ServiceStackIDEA/.idea/misc.xml b/src/ServiceStackIDEA/.idea/misc.xml index 0fce18e1..ed6db134 100644 --- a/src/ServiceStackIDEA/.idea/misc.xml +++ b/src/ServiceStackIDEA/.idea/misc.xml @@ -3,17 +3,7 @@ - - - - - - - - - - - + \ No newline at end of file diff --git a/src/ServiceStackIDEA/.idea/workspace.xml b/src/ServiceStackIDEA/.idea/workspace.xml index e8ed1eb5..933140bb 100644 --- a/src/ServiceStackIDEA/.idea/workspace.xml +++ b/src/ServiceStackIDEA/.idea/workspace.xml @@ -5,12 +5,23 @@ - - - - - - + + + + + + + + + + + + + + + + + @@ -24,11 +35,9 @@ - - @@ -42,98 +51,29 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -56,88 +51,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UpdateServiceStackUtils - - - - - @@ -213,20 +74,12 @@ - - + - - - - - - - - - + + @@ -234,7 +87,7 @@ - + @@ -247,18 +100,6 @@ - - - @@ -297,6 +138,12 @@ + + @@ -491,6 +338,15 @@ + + + project @@ -513,12 +369,6 @@ - - - + + - - - @@ -662,6 +504,18 @@ + + - - - - file://$PROJECT_DIR$/src/main/java/net/servicestack/idea/IDEAUtils.java - 71 - - - diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddRef.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddRef.java index bb1f2f81..c89d6722 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddRef.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddRef.java @@ -224,7 +224,7 @@ private void processOK() { JsonElement jElement = new JsonParser().parse(builder.toString()); if (jElement.getAsJsonArray().size() > 0) { String latestTag = jElement.getAsJsonArray().get(0).getAsJsonObject().get("name").getAsJsonPrimitive().getAsString(); - AddServiceStackRefHandler.setDependencyVersion(latestTag.substring(1)); + DepConfig.setServiceStackVersion(latestTag.substring(1)); } } catch (MalformedURLException e) { diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackAction.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackAction.java index 9629d973..b4c3ad6f 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackAction.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackAction.java @@ -35,7 +35,7 @@ public void actionPerformed(AnActionEvent e) { //Check if a package was selected in the left hand menu, populate package name PsiElement element = LangDataKeys.PSI_ELEMENT.getData(e.getDataContext()); - if (element != null && element instanceof PsiPackage) { + if (element instanceof PsiPackage) { PsiPackage psiPackage = (PsiPackage) element; dialog.setSelectedPackage(psiPackage); dialog.setVisible(true); @@ -43,10 +43,10 @@ public void actionPerformed(AnActionEvent e) { } //Check if a directory containing a Java file was selected, populate package name - if (element != null && element instanceof PsiDirectory) { + if (element instanceof PsiDirectory) { PsiElement firstChild = element.getFirstChild(); dialog.setSelectedDirectory(((PsiDirectory) element).getVirtualFile().getPath()); - if (firstChild != null && firstChild instanceof PsiJavaFile) { + if (firstChild instanceof PsiJavaFile) { PsiJavaFile firstJavaFile = (PsiJavaFile) firstChild; PsiPackage mainPackage = JavaPsiFacade.getInstance(module.getProject()).findPackage(firstJavaFile.getPackageName()); if (mainPackage != null) { diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackRefHandler.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackRefHandler.java index 7d15f0ae..e882ae16 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackRefHandler.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackRefHandler.java @@ -23,19 +23,8 @@ public class AddServiceStackRefHandler { - private static final String dependencyGroupId = "net.servicestack"; - private static final String androidPackageId = "android"; - //Fallback version of dependencies if GitHub tags can't be checked. - private static String dependencyVersion = "1.0.38"; - private static final String clientPackageId = "client"; - private static INativeTypesHandler defaultNativeTypesHandler; - public static void setDependencyVersion(String version) { - dependencyVersion = version; - } - - public static void handleOk(String addressUrl, String qualifiedPackageName, String fileName, String selectedDirectory, Module module, StringBuilder errorMessage) { @@ -53,7 +42,7 @@ public static void handleOk(String addressUrl, String qualifiedPackageName, } catch (FileNotFoundException e) { e.printStackTrace(); String message = "Failed to update build.gradle with '" + - dependencyGroupId + ":" + clientPackageId + ":" + dependencyVersion + + DepConfig.getClientVersionString() + "'. " + e.getLocalizedMessage(); Notification notification = new Notification( "ServiceStackIDEA", @@ -95,13 +84,9 @@ private static List getDtoLines(String addressUrl, String qualifiedPacka return null; } } - catch (URISyntaxException e) { - e.printStackTrace(); - DialogErrorMessages.appendInvalidEnpoint(errorMessage, addressUrl, e); - return null; - } catch (MalformedURLException e) { + catch (URISyntaxException | MalformedURLException e) { e.printStackTrace(); - DialogErrorMessages.appendInvalidEnpoint(errorMessage, addressUrl, e); + DialogErrorMessages.appendInvalidEndpoint(errorMessage, addressUrl, e); return null; } catch (IOException e) { e.printStackTrace(); @@ -122,7 +107,7 @@ private static INativeTypesHandler getNativeTypesHandler(String fileName) { private static boolean tryAddMavenDependency(Module module) { boolean showDto; String message = "Unable to locate module pom.xml file. Can't add required dependency '" + - dependencyGroupId + ":" + clientPackageId + ":" + dependencyVersion + + DepConfig.getClientVersionString() + "'."; Notification notification = new Notification( "ServiceStackIDEA", @@ -137,7 +122,8 @@ private static boolean tryAddMavenDependency(Module module) { return false; } File pomLibFile = new File(pomFilePath); - showDto = pomFileHelper.addMavenDependency(module,pomLibFile, dependencyGroupId, clientPackageId, dependencyVersion); + showDto = pomFileHelper.addMavenDependency(module,pomLibFile, DepConfig.servicestackGroupId, DepConfig.clientPackageId, DepConfig.servicestackVersion) || + pomFileHelper.addMavenDependency(module,pomLibFile, DepConfig.gsonGroupId, DepConfig.gsonPackageId, DepConfig.gsonVersion); IDEAUtils.refreshFile(module,pomFilePath,showDto); } catch(Exception e) { showDto = false; @@ -153,12 +139,12 @@ private static boolean tryAddMavenDependency(Module module) { } private static boolean addGradleDependencyIfRequired(Module module) throws FileNotFoundException { - boolean result = false; - if(GradleBuildFileHelper.addDependency(module,dependencyGroupId, androidPackageId, dependencyVersion)) { - result = true; + if (GradleBuildFileHelper.addDependency(module, DepConfig.servicestackGroupId, DepConfig.androidPackageId, DepConfig.servicestackVersion) || + GradleBuildFileHelper.addDependency(module, DepConfig.gsonGroupId, DepConfig.gsonPackageId, DepConfig.gsonVersion)) { IDEAUtils.refreshBuildFile(module); + return true; } - return result; + return false; } private static String getDtoPath(Module module, String qualifiedPackageName, String selectedDirectory, String fileName, StringBuilder errorMessage) throws FileNotFoundException { @@ -199,8 +185,7 @@ private static String getDtoPath(Module module, String qualifiedPackageName, Str public static String getDtoFileName(String name) { INativeTypesHandler nativeTypesHandler = getNativeTypesHandler(name); int p = name.lastIndexOf("."); - String e = name.substring(p); - if (p == -1 || !e.equals(nativeTypesHandler.getFileExtension())) { + if (p == -1 || !name.substring(p).equals(nativeTypesHandler.getFileExtension())) { /* file has no extension */ return name + nativeTypesHandler.getFileExtension(); } else { @@ -212,8 +197,7 @@ public static String getDtoFileName(String name) { public static String getDtoNameWithoutExtension(String name) { INativeTypesHandler nativeTypesHandler = getNativeTypesHandler(name); int p = name.lastIndexOf("."); - String e = name.substring(p); - if (p == -1 || !e.equals(nativeTypesHandler.getFileExtension())) { + if (p == -1 || !name.substring(p).equals(nativeTypesHandler.getFileExtension())) { /* file has no extension */ return name; } else { diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddTypeScriptAction.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddTypeScriptAction.java index 2e90cc09..3a57c28a 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddTypeScriptAction.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddTypeScriptAction.java @@ -27,7 +27,7 @@ public void actionPerformed(AnActionEvent anActionEvent) { dialog.setTitle("Add TypeScript ServiceStack Reference"); PsiElement element = LangDataKeys.PSI_ELEMENT.getData(anActionEvent.getDataContext()); INativeTypesHandler defaultTsNativeTypesHandler = new TypeScriptNativeTypesHandler(); - if (element != null && element instanceof PsiDirectory) { + if (element instanceof PsiDirectory) { PsiDirectory selectedDir = (PsiDirectory)element; dialog.setSelectedDirectory(selectedDir.getVirtualFile().getPath()); String initialName = getInitialFileName(selectedDir.getVirtualFile().getPath(),defaultTsNativeTypesHandler); @@ -58,11 +58,11 @@ private String getInitialFileName(String path, INativeTypesHandler defaultTsNati @Override public void update(AnActionEvent e) { Module module = getModule(e); - if(module == null) { + if (module == null) { e.getPresentation().setEnabled(false); } - if(!(PlatformUtils.isWebStorm() || PlatformUtils.isPhpStorm() || + if (!(PlatformUtils.isWebStorm() || PlatformUtils.isPhpStorm() || PlatformUtils.isRubyMine() || PlatformUtils.isIntelliJ() || PlatformUtils.isPyCharm())) { e.getPresentation().setVisible(false); diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddTypeScriptRefHandler.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddTypeScriptRefHandler.java index acc7c439..95ed24a6 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddTypeScriptRefHandler.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddTypeScriptRefHandler.java @@ -53,21 +53,11 @@ private static List getDtoLines(String addressUrl, INativeTypesHandler n errorMessage.append("The address url is not a valid ServiceStack endpoint."); return null; } - } catch (URISyntaxException e) { + } catch (URISyntaxException | MalformedURLException | FileNotFoundException e) { e.printStackTrace(); - DialogErrorMessages.appendInvalidEnpoint(errorMessage, addressUrl, e); + DialogErrorMessages.appendInvalidEndpoint(errorMessage, addressUrl, e); return null; - } catch (MalformedURLException e) { - e.printStackTrace(); - DialogErrorMessages.appendInvalidEnpoint(errorMessage, addressUrl, e); - return null; - } - catch (FileNotFoundException e) { - e.printStackTrace(); - DialogErrorMessages.appendInvalidEnpoint(errorMessage, addressUrl, e); - return null; - } - catch (IOException e) { + } catch (IOException e) { e.printStackTrace(); DialogErrorMessages.appendReadResponseError(errorMessage, addressUrl, e); return null; diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/Analytics.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/Analytics.java index 7e96c3dc..bf50eedc 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/Analytics.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/Analytics.java @@ -26,7 +26,7 @@ public static void SubmitAnonymousUpdateReferenceUsage(INativeTypesHandler types public static void SubmitAnonymousUsage(final String url) { PluginSettingsService settings = PluginSettingsService.getInstance(); - if (!settings.optOutOfStats) { + if (!settings.optOutOfStats && !"1".equals(System.getenv("SERVICESTACK_TELEMETRY_OPTOUT"))) { final URL[] serviceUrl = {null}; final URLConnection[] responseConnection = {null}; final BufferedReader[] responseReader = {null}; @@ -36,10 +36,7 @@ public void run() { try { serviceUrl[0] = new URL(url); responseConnection[0] = serviceUrl[0].openConnection(); - responseReader[0] = new BufferedReader( - new InputStreamReader( - responseConnection[0].getInputStream())); - + responseReader[0] = new BufferedReader(new InputStreamReader(responseConnection[0].getInputStream())); responseReader[0].close(); } catch (IOException e) { // Ignore failure (eg no internet connection). diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DepConfig.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DepConfig.java new file mode 100644 index 00000000..bb77ba64 --- /dev/null +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DepConfig.java @@ -0,0 +1,22 @@ +package net.servicestack.idea; + +public class DepConfig { + public static final String servicestackGroupId = "net.servicestack"; + public static final String androidPackageId = "android"; + //Fallback version of dependencies if GitHub tags can't be checked. + public static final String clientPackageId = "client"; + public static String servicestackVersion = "1.0.38"; + + public static final String gsonGroupId = "com.google.code.gson"; + public static final String gsonPackageId = "gson"; + public static String gsonVersion = "2.8.6"; + + public static void setServiceStackVersion(String version) { + servicestackVersion = version; + } + + public static String getClientVersionString() { + return servicestackGroupId + ":" + clientPackageId + ":" + servicestackVersion; + } + +} \ No newline at end of file diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DialogErrorMessages.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DialogErrorMessages.java index e168e650..28898612 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DialogErrorMessages.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DialogErrorMessages.java @@ -8,7 +8,7 @@ * Helper messages for common add reference dialog errors. */ public class DialogErrorMessages { - public static StringBuilder appendInvalidEnpoint(StringBuilder errorMessage,String addressUrl, Exception e) { + public static StringBuilder appendInvalidEndpoint(StringBuilder errorMessage, String addressUrl, Exception e) { errorMessage.append(e.getClass().getName()).append(" - Invalid ServiceStack endpoint provided - ").append(addressUrl); return errorMessage; } diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/GradleBuildFileHelper.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/GradleBuildFileHelper.java index 2d32e83a..5a95c372 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/GradleBuildFileHelper.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/GradleBuildFileHelper.java @@ -41,7 +41,7 @@ public static boolean addDependency(Module module,String groupId, String package e.printStackTrace(); } - if(dependenciesStartIndex == -1 || dependenciesEndIndex == -1) { + if (dependenciesStartIndex == -1 || dependenciesEndIndex == -1) { return false; } @@ -55,7 +55,7 @@ public static boolean addDependency(Module module,String groupId, String package } } - if(!dependencyRequired) { + if (!dependencyRequired) { return false; } list.add(dependenciesEndIndex, " implementation '" + groupId + ":" + packageName + ":" + version + "'"); @@ -76,14 +76,14 @@ public static Boolean isGradleModule(Module module) { } public static Boolean isUsingKotlin(Module module){ - if(!isGradleModule(module)) { + if (!isGradleModule(module)) { return false; } File buildFile = getGradleBuildFile(module); - if(buildFile == null) { + if (buildFile == null) { return false; } - Boolean result = false; + boolean result = false; try { BufferedReader br = new BufferedReader(new FileReader(buildFile)); for (String line; (line = br.readLine()) != null; ) { diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/IDEAPomFileHelper.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/IDEAPomFileHelper.java index 15637698..554f12e9 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/IDEAPomFileHelper.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/IDEAPomFileHelper.java @@ -33,22 +33,18 @@ public class IDEAPomFileHelper { public boolean addMavenDependency(final Module module,File pomFile, String groupId, String packageId, String version) throws Exception { - boolean dependencyAdded = false; try { - if(!pomHasMavenDependency(pomFile,groupId,packageId)) { + if (!pomHasMavenDependency(pomFile,groupId,packageId)) { PomAppendDependency(module, pomFile,groupId,packageId,version); - dependencyAdded = true; + return true; } - } catch (IOException e) { - e.printStackTrace(); - throw new Exception("Unable to process pom.xml to add " + groupId + ":" + packageId + ":" + version); - } catch (ParserConfigurationException e) { + } catch (IOException | ParserConfigurationException e) { e.printStackTrace(); throw new Exception("Unable to process pom.xml to add " + groupId + ":" + packageId + ":" + version); } - return dependencyAdded; + return false; } @@ -123,60 +119,52 @@ private static boolean pomHasDependenciesNode(Document document) { private static Node getMavenDependenciesNode(Document document) { Node rootNode = document.getFirstChild(); - NodeList firstChildern = rootNode.getChildNodes(); - Node result = null; - for(int i = 0; i < firstChildern.getLength(); i++) { - Node child = firstChildern.item(i); - if(child == null) { + NodeList firstChildren = rootNode.getChildNodes(); + for (int i = 0; i < firstChildren.getLength(); i++) { + Node child = firstChildren.item(i); + if (child == null) { continue; } - if(child.getNodeName().equals("dependencies")) { - result = child; - break; + if (child.getNodeName().equals("dependencies")) { + return child; } } - return result; + return null; } public static boolean pomHasMavenDependency(File pomFile, String groupId, String packageId) throws ParserConfigurationException, IOException, SAXException { - boolean hasDependency = false; DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); Document doc = docBuilder.parse(pomFile); - if(!pomHasDependenciesNode(doc)) { + if (!pomHasDependenciesNode(doc)) { return false; } Node dependencies = getMavenDependenciesNode(doc); NodeList depElements = dependencies.getChildNodes(); - for(int i = 0; i < depElements.getLength(); i++) { + for (int i = 0; i < depElements.getLength(); i++) { Node dependencyElement = depElements.item(i); - if(pomDependencyElementMatch(dependencyElement, groupId,packageId)) { - hasDependency = true; - break; + if (pomDependencyElementMatch(dependencyElement, groupId, packageId)) { + return true; } } - return hasDependency; + return false; } public static boolean pomHasKotlinDependency(Module module) { String pomFilePath = findNearestModulePomFile(module); - if(pomFilePath == null) { + if (pomFilePath == null) { return false; } File pomFile = new File(pomFilePath); - if(!pomFile.exists()) { + if (!pomFile.exists()) { return false; } try { return pomHasMavenDependency(pomFile,"org.jetbrains.kotlin","kotlin-stdlib"); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (SAXException e) { + } catch (ParserConfigurationException | IOException | SAXException e) { e.printStackTrace(); } return false; diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/IDEAUtils.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/IDEAUtils.java index 6483343e..722ef104 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/IDEAUtils.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/IDEAUtils.java @@ -92,15 +92,15 @@ public static void closeFile(Module module, String filePath) { } public static INativeTypesHandler getDefaultNativeTypesHandler(Module module) { - if(GradleBuildFileHelper.isGradleModule(module) && GradleBuildFileHelper.isUsingKotlin(module)) { + if (GradleBuildFileHelper.isGradleModule(module) && GradleBuildFileHelper.isUsingKotlin(module)) { return new KotlinNativeTypesHandler(); } - if(IDEAPomFileHelper.isMavenProjectWithKotlin(module)) { + if (IDEAPomFileHelper.isMavenProjectWithKotlin(module)) { return new KotlinNativeTypesHandler(); } - if(PlatformUtils.isWebStorm()) { + if (PlatformUtils.isWebStorm()) { return new TypeScriptConcreteNativeTypesHandler(); } @@ -109,10 +109,10 @@ public static INativeTypesHandler getDefaultNativeTypesHandler(Module module) { public static INativeTypesHandler getNativeTypesHandler(String fileName) { INativeTypesHandler result = null; - if(fileName.endsWith(".kt")) result = new KotlinNativeTypesHandler(); - if(fileName.endsWith(".java")) result = new JavaNativeTypesHandler(); - if(fileName.endsWith(".dtos.ts")) result = new TypeScriptConcreteNativeTypesHandler(); - if(fileName.endsWith(".dtos.d.ts")) result = new TypeScriptNativeTypesHandler(); + if (fileName.endsWith(".kt")) result = new KotlinNativeTypesHandler(); + if (fileName.endsWith(".java")) result = new JavaNativeTypesHandler(); + if (fileName.endsWith(".dtos.ts")) result = new TypeScriptConcreteNativeTypesHandler(); + if (fileName.endsWith(".dtos.d.ts")) result = new TypeScriptNativeTypesHandler(); return result; } } From 87e76fafa818d7c05a65df610334b1371f418575 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 1 Feb 2020 18:00:52 -0500 Subject: [PATCH 088/211] bump to v1.0.39 --- src/AndroidClient/android/build.gradle | 2 +- src/AndroidClient/androidchat/build.gradle | 2 +- src/AndroidClient/client/build.gradle | 2 +- src/AndroidClient/client/pom.xml | 2 +- .../eclipse/wizard/AddReferenceWizard.java | 2 +- src/ServiceStackIDEA/.idea/workspace.xml | 25 +++++-------------- src/ServiceStackIDEA/build.gradle | 4 +-- .../java/net/servicestack/idea/DepConfig.java | 2 +- 8 files changed, 14 insertions(+), 27 deletions(-) diff --git a/src/AndroidClient/android/build.gradle b/src/AndroidClient/android/build.gradle index e0d6ae9e..868226be 100644 --- a/src/AndroidClient/android/build.gradle +++ b/src/AndroidClient/android/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.library' apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' -version = "1.0.38" +version = "1.0.39" dependencies { implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.6' diff --git a/src/AndroidClient/androidchat/build.gradle b/src/AndroidClient/androidchat/build.gradle index 43151bc1..927d6bbd 100644 --- a/src/AndroidClient/androidchat/build.gradle +++ b/src/AndroidClient/androidchat/build.gradle @@ -52,7 +52,7 @@ dependencies { implementation project(':android') implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support:design:28.0.0' - implementation 'net.servicestack:android:1.0.38' + implementation 'net.servicestack:android:1.0.39' implementation 'com.facebook.android:facebook-android-sdk:4.31.0' implementation('com.twitter.sdk.android:twitter:2.3.1@aar') { transitive = true; diff --git a/src/AndroidClient/client/build.gradle b/src/AndroidClient/client/build.gradle index 2b715b74..e55e48cf 100644 --- a/src/AndroidClient/client/build.gradle +++ b/src/AndroidClient/client/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' -version = "1.0.38" +version = "1.0.39" dependencies { implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.6' diff --git a/src/AndroidClient/client/pom.xml b/src/AndroidClient/client/pom.xml index ccde3204..b5ce4ced 100644 --- a/src/AndroidClient/client/pom.xml +++ b/src/AndroidClient/client/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.servicestack client - 1.0.38 + 1.0.39 ServiceStack.Client A client library to call your ServiceStack webservices. https://github.com/ServiceStack/ServiceStack.Java diff --git a/src/ServiceStackEclipse/ServiceStackEclipse.Bundle/src/main/java/net/servicestack/eclipse/wizard/AddReferenceWizard.java b/src/ServiceStackEclipse/ServiceStackEclipse.Bundle/src/main/java/net/servicestack/eclipse/wizard/AddReferenceWizard.java index 1e4d60ad..0a56a32b 100644 --- a/src/ServiceStackEclipse/ServiceStackEclipse.Bundle/src/main/java/net/servicestack/eclipse/wizard/AddReferenceWizard.java +++ b/src/ServiceStackEclipse/ServiceStackEclipse.Bundle/src/main/java/net/servicestack/eclipse/wizard/AddReferenceWizard.java @@ -40,7 +40,7 @@ public class AddReferenceWizard extends Wizard { boolean packageSelected = false; private static final String dependencyGroupId = "net.servicestack"; - private static final String dependencyVersion = "1.0.38"; + private static final String dependencyVersion = "1.0.39"; private static final String clientPackageId = "client"; private static final String gsonDependencyGroupId = "com.google.code.gson"; diff --git a/src/ServiceStackIDEA/.idea/workspace.xml b/src/ServiceStackIDEA/.idea/workspace.xml index 67fff2e4..8481e972 100644 --- a/src/ServiceStackIDEA/.idea/workspace.xml +++ b/src/ServiceStackIDEA/.idea/workspace.xml @@ -5,21 +5,8 @@ - - - - - - - - - - - - - - - + + - + - - + + - + diff --git a/src/ServiceStackIDEA/build.gradle b/src/ServiceStackIDEA/build.gradle index 21581176..639b9d96 100644 --- a/src/ServiceStackIDEA/build.gradle +++ b/src/ServiceStackIDEA/build.gradle @@ -1,7 +1,7 @@ plugins { id "org.jetbrains.intellij" version "0.4.15" } -version = '1.0.38' +version = '1.0.39' apply plugin: 'org.jetbrains.intellij' dependencies { @@ -15,7 +15,7 @@ if(System.env.BUILD_NUMBER != null && System.env.SERVICESTACKIDEA_PUBLISH_NIGHTL String jbToken; -if(properties.getProperty("jetbrains.plugins.user", null) == null) { +if (properties.getProperty("jetbrains.plugins.user", null) == null) { properties.load(project.file('./local.properties').newDataInputStream()) } jbToken = properties.getProperty("jetbrains.plugins.token"); diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DepConfig.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DepConfig.java index bb77ba64..fe6cea58 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DepConfig.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DepConfig.java @@ -5,7 +5,7 @@ public class DepConfig { public static final String androidPackageId = "android"; //Fallback version of dependencies if GitHub tags can't be checked. public static final String clientPackageId = "client"; - public static String servicestackVersion = "1.0.38"; + public static String servicestackVersion = "1.0.39"; public static final String gsonGroupId = "com.google.code.gson"; public static final String gsonPackageId = "gson"; From 808d938e0577d704638e56eb5b1166ab4a84e46b Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 1 Feb 2020 18:22:25 -0500 Subject: [PATCH 089/211] Always try to add gson dep --- src/ServiceStackIDEA/.idea/workspace.xml | 8 ++++---- .../idea/AddServiceStackRefHandler.java | 15 ++++++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/ServiceStackIDEA/.idea/workspace.xml b/src/ServiceStackIDEA/.idea/workspace.xml index 8481e972..4edaae42 100644 --- a/src/ServiceStackIDEA/.idea/workspace.xml +++ b/src/ServiceStackIDEA/.idea/workspace.xml @@ -5,8 +5,8 @@ - - + + diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackRefHandler.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackRefHandler.java index e882ae16..56ac7713 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackRefHandler.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackRefHandler.java @@ -117,13 +117,15 @@ private static boolean tryAddMavenDependency(Module module) { try { IDEAPomFileHelper pomFileHelper = new IDEAPomFileHelper(); String pomFilePath = IDEAPomFileHelper.findNearestModulePomFile(module); - if(pomFilePath == null) { + if (pomFilePath == null) { Notifications.Bus.notify(notification); return false; } File pomLibFile = new File(pomFilePath); - showDto = pomFileHelper.addMavenDependency(module,pomLibFile, DepConfig.servicestackGroupId, DepConfig.clientPackageId, DepConfig.servicestackVersion) || - pomFileHelper.addMavenDependency(module,pomLibFile, DepConfig.gsonGroupId, DepConfig.gsonPackageId, DepConfig.gsonVersion); + showDto = pomFileHelper.addMavenDependency(module,pomLibFile, DepConfig.servicestackGroupId, DepConfig.clientPackageId, DepConfig.servicestackVersion); + if (pomFileHelper.addMavenDependency(module,pomLibFile, DepConfig.gsonGroupId, DepConfig.gsonPackageId, DepConfig.gsonVersion)) + showDto = true; + IDEAUtils.refreshFile(module,pomFilePath,showDto); } catch(Exception e) { showDto = false; @@ -139,8 +141,11 @@ private static boolean tryAddMavenDependency(Module module) { } private static boolean addGradleDependencyIfRequired(Module module) throws FileNotFoundException { - if (GradleBuildFileHelper.addDependency(module, DepConfig.servicestackGroupId, DepConfig.androidPackageId, DepConfig.servicestackVersion) || - GradleBuildFileHelper.addDependency(module, DepConfig.gsonGroupId, DepConfig.gsonPackageId, DepConfig.gsonVersion)) { + boolean depAdded = GradleBuildFileHelper.addDependency(module, DepConfig.servicestackGroupId, DepConfig.androidPackageId, DepConfig.servicestackVersion); + if (GradleBuildFileHelper.addDependency(module, DepConfig.gsonGroupId, DepConfig.gsonPackageId, DepConfig.gsonVersion)) + depAdded = true; + + if (depAdded) { IDEAUtils.refreshBuildFile(module); return true; } From 68dba3c7094e8e2bb2febb560e1cd368beeb528c Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 1 Feb 2020 18:23:45 -0500 Subject: [PATCH 090/211] bump to v1.0.40 --- src/AndroidClient/android/build.gradle | 2 +- src/AndroidClient/androidchat/build.gradle | 2 +- src/AndroidClient/client/build.gradle | 2 +- src/AndroidClient/client/pom.xml | 2 +- .../servicestack/eclipse/wizard/AddReferenceWizard.java | 2 +- src/ServiceStackIDEA/.idea/workspace.xml | 8 +++++--- src/ServiceStackIDEA/build.gradle | 2 +- .../src/main/java/net/servicestack/idea/DepConfig.java | 2 +- 8 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/AndroidClient/android/build.gradle b/src/AndroidClient/android/build.gradle index 868226be..e8a6e894 100644 --- a/src/AndroidClient/android/build.gradle +++ b/src/AndroidClient/android/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.library' apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' -version = "1.0.39" +version = "1.0.40" dependencies { implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.6' diff --git a/src/AndroidClient/androidchat/build.gradle b/src/AndroidClient/androidchat/build.gradle index 927d6bbd..c9c02b7e 100644 --- a/src/AndroidClient/androidchat/build.gradle +++ b/src/AndroidClient/androidchat/build.gradle @@ -52,7 +52,7 @@ dependencies { implementation project(':android') implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support:design:28.0.0' - implementation 'net.servicestack:android:1.0.39' + implementation 'net.servicestack:android:1.0.40' implementation 'com.facebook.android:facebook-android-sdk:4.31.0' implementation('com.twitter.sdk.android:twitter:2.3.1@aar') { transitive = true; diff --git a/src/AndroidClient/client/build.gradle b/src/AndroidClient/client/build.gradle index e55e48cf..777556dd 100644 --- a/src/AndroidClient/client/build.gradle +++ b/src/AndroidClient/client/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' -version = "1.0.39" +version = "1.0.40" dependencies { implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.6' diff --git a/src/AndroidClient/client/pom.xml b/src/AndroidClient/client/pom.xml index b5ce4ced..fe8186cc 100644 --- a/src/AndroidClient/client/pom.xml +++ b/src/AndroidClient/client/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.servicestack client - 1.0.39 + 1.0.40 ServiceStack.Client A client library to call your ServiceStack webservices. https://github.com/ServiceStack/ServiceStack.Java diff --git a/src/ServiceStackEclipse/ServiceStackEclipse.Bundle/src/main/java/net/servicestack/eclipse/wizard/AddReferenceWizard.java b/src/ServiceStackEclipse/ServiceStackEclipse.Bundle/src/main/java/net/servicestack/eclipse/wizard/AddReferenceWizard.java index 0a56a32b..0a64f9c0 100644 --- a/src/ServiceStackEclipse/ServiceStackEclipse.Bundle/src/main/java/net/servicestack/eclipse/wizard/AddReferenceWizard.java +++ b/src/ServiceStackEclipse/ServiceStackEclipse.Bundle/src/main/java/net/servicestack/eclipse/wizard/AddReferenceWizard.java @@ -40,7 +40,7 @@ public class AddReferenceWizard extends Wizard { boolean packageSelected = false; private static final String dependencyGroupId = "net.servicestack"; - private static final String dependencyVersion = "1.0.39"; + private static final String dependencyVersion = "1.0.40"; private static final String clientPackageId = "client"; private static final String gsonDependencyGroupId = "com.google.code.gson"; diff --git a/src/ServiceStackIDEA/.idea/workspace.xml b/src/ServiceStackIDEA/.idea/workspace.xml index 4edaae42..8444637a 100644 --- a/src/ServiceStackIDEA/.idea/workspace.xml +++ b/src/ServiceStackIDEA/.idea/workspace.xml @@ -5,8 +5,10 @@ + - + + diff --git a/src/ServiceStackIDEA/build.gradle b/src/ServiceStackIDEA/build.gradle index 639b9d96..459428bf 100644 --- a/src/ServiceStackIDEA/build.gradle +++ b/src/ServiceStackIDEA/build.gradle @@ -1,7 +1,7 @@ plugins { id "org.jetbrains.intellij" version "0.4.15" } -version = '1.0.39' +version = '1.0.40' apply plugin: 'org.jetbrains.intellij' dependencies { diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DepConfig.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DepConfig.java index fe6cea58..6229f94d 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DepConfig.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DepConfig.java @@ -5,7 +5,7 @@ public class DepConfig { public static final String androidPackageId = "android"; //Fallback version of dependencies if GitHub tags can't be checked. public static final String clientPackageId = "client"; - public static String servicestackVersion = "1.0.39"; + public static String servicestackVersion = "1.0.40"; public static final String gsonGroupId = "com.google.code.gson"; public static final String gsonPackageId = "gson"; From 4fba5c21e21df46de71b96ac7d16fb8723a59d5d Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 1 Feb 2020 18:31:56 -0500 Subject: [PATCH 091/211] bump to v1.0.14 --- src/ServiceStackIDEA/.idea/workspace.xml | 11 +++-------- .../src/main/resources/META-INF/plugin.xml | 3 ++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/ServiceStackIDEA/.idea/workspace.xml b/src/ServiceStackIDEA/.idea/workspace.xml index 8444637a..470debe4 100644 --- a/src/ServiceStackIDEA/.idea/workspace.xml +++ b/src/ServiceStackIDEA/.idea/workspace.xml @@ -4,12 +4,7 @@ - - - - - - + diff --git a/src/ServiceStackIDEA/src/main/resources/META-INF/plugin.xml b/src/ServiceStackIDEA/src/main/resources/META-INF/plugin.xml index 6d6eaa6c..e690fee0 100644 --- a/src/ServiceStackIDEA/src/main/resources/META-INF/plugin.xml +++ b/src/ServiceStackIDEA/src/main/resources/META-INF/plugin.xml @@ -2,7 +2,7 @@ net.servicestack.ideaplugin ServiceStack - 1.0.13 + 1.0.14 ServiceStack +
  • 1.0.14 - Fix adding Android dependencies.
  • 1.0.12 - Fix TypeScript dialog defaults to use classes over definitions only.
  • 1.0.11 - Small UI fixes.
  • 1.0.10 - Add TypeScript support. Fix issue with resolving URL to match behavior of other extensions.
  • From 6026ce6d09428c9b3584e7b43a990c8a657eb78d Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Mon, 3 Feb 2020 15:58:03 -0500 Subject: [PATCH 092/211] Add Dart ServiceStack Reference support --- src/ServiceStackIDEA/.idea/workspace.xml | 19 ++++++++++-- .../idea/AddServiceStackAction.java | 13 +++++---- .../idea/DartNativeTypesHandler.java | 18 ++++++++++++ .../idea/GradleBuildFileHelper.java | 29 +++++++++++++------ .../java/net/servicestack/idea/IDEAUtils.java | 19 ++++++------ .../idea/NativeTypesLanguage.java | 1 + .../idea/UpdateServiceStackUtils.java | 20 ++++++------- .../src/main/resources/META-INF/plugin.xml | 3 +- 8 files changed, 85 insertions(+), 37 deletions(-) create mode 100644 src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DartNativeTypesHandler.java diff --git a/src/ServiceStackIDEA/.idea/workspace.xml b/src/ServiceStackIDEA/.idea/workspace.xml index 470debe4..292ef8ff 100644 --- a/src/ServiceStackIDEA/.idea/workspace.xml +++ b/src/ServiceStackIDEA/.idea/workspace.xml @@ -4,7 +4,16 @@
    - + + + + + + + + + + diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackAction.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackAction.java index b4c3ad6f..049066ef 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackAction.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackAction.java @@ -52,7 +52,7 @@ public void actionPerformed(AnActionEvent e) { if (mainPackage != null) { dialog.setSelectedPackage(mainPackage); } - } else if(module.getModuleFile() != null) { + } else if (module.getModuleFile() != null) { try { PsiDirectory selectedDir = (PsiDirectory) element; String packageName = ""; @@ -122,13 +122,16 @@ public void actionPerformed(AnActionEvent e) { } private void ShowDialog(Module module, AddRef dialog) { - if(GradleBuildFileHelper.isGradleModule(module) && GradleBuildFileHelper.isUsingKotlin(module)) { + if (GradleBuildFileHelper.isGradleModule(module) && GradleBuildFileHelper.isUsingKotlin(module)) { dialog.setFileName("dtos.kt"); } - - if(IDEAPomFileHelper.isMavenProjectWithKotlin(module)) { + else if (IDEAPomFileHelper.isMavenProjectWithKotlin(module)) { dialog.setFileName("dtos.kt"); } + else if (GradleBuildFileHelper.isDartProject(module)) { + dialog.setFileName("dtos.dart"); + } + dialog.setVisible(true); } @@ -152,7 +155,7 @@ public void update(AnActionEvent e) { return; } - if(!(PlatformUtils.isIntelliJ() || isAndroidProject(module))) { + if (!(PlatformUtils.isIntelliJ() || isAndroidProject(module))) { e.getPresentation().setVisible(false); return; } diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DartNativeTypesHandler.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DartNativeTypesHandler.java new file mode 100644 index 00000000..7acc5539 --- /dev/null +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/DartNativeTypesHandler.java @@ -0,0 +1,18 @@ +package net.servicestack.idea; + +public class DartNativeTypesHandler extends BaseNativeTypesHandler { + @Override + public String getFileExtension() { + return ".dart"; + } + + @Override + public String getRelativeTypesUrl() { + return "types/dart"; + } + + @Override + public NativeTypesLanguage getTypesLanguage() { + return NativeTypesLanguage.Dart; + } +} diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/GradleBuildFileHelper.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/GradleBuildFileHelper.java index 5a95c372..1647de77 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/GradleBuildFileHelper.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/GradleBuildFileHelper.java @@ -75,6 +75,10 @@ public static Boolean isGradleModule(Module module) { return getGradleBuildFile(module) != null; } + public static Boolean isDartProject(Module module) { + return getDartPubspec(module) != null; + } + public static Boolean isUsingKotlin(Module module){ if (!isGradleModule(module)) { return false; @@ -102,20 +106,27 @@ public static Boolean isUsingKotlin(Module module){ public static File getGradleBuildFile(Module module) { VirtualFile moduleFile = module.getModuleFile(); - if(moduleFile == null) { + if (moduleFile == null) { return null; } String moduleDirectory = moduleFile.getParent().getPath(); File file = new File(moduleDirectory); - File[] matchingFiles = file.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.startsWith("build.gradle"); - } - }); - if(matchingFiles == null || matchingFiles.length == 0) { + File[] matchingFiles = file.listFiles((dir, name) -> name.startsWith("build.gradle")); + return matchingFiles == null || matchingFiles.length == 0 + ? null + : matchingFiles[0]; + } + + public static File getDartPubspec(Module module) { + VirtualFile moduleFile = module.getModuleFile(); + if (moduleFile == null) { return null; } - return matchingFiles[0]; + String moduleDirectory = moduleFile.getParent().getPath(); + File file = new File(moduleDirectory); + File[] matchingFiles = file.listFiles((dir, name) -> name.startsWith("pubspec.yaml")); + return matchingFiles == null || matchingFiles.length == 0 + ? null + : matchingFiles[0]; } } diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/IDEAUtils.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/IDEAUtils.java index 722ef104..fc912da3 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/IDEAUtils.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/IDEAUtils.java @@ -11,6 +11,7 @@ import com.intellij.util.PlatformUtils; import java.io.*; +import java.nio.charset.StandardCharsets; import java.util.List; /** @@ -54,16 +55,11 @@ public static void refreshFile(Module module, String filePath, boolean openFile) VirtualFileManager.getInstance().syncRefresh(); } - public static void refreshFile(String filePath, boolean openFile) { - - } - public static boolean writeDtoFile(List codeLines, String path, StringBuilder errorMessage) { BufferedWriter writer = null; boolean result = true; try { - writer = new BufferedWriter(new OutputStreamWriter( - new FileOutputStream(path), "utf-8")); + writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path), StandardCharsets.UTF_8)); for (String item : codeLines) { writer.write(item); writer.newLine(); @@ -100,6 +96,10 @@ public static INativeTypesHandler getDefaultNativeTypesHandler(Module module) { return new KotlinNativeTypesHandler(); } + if (GradleBuildFileHelper.isDartProject(module)) { + return new DartNativeTypesHandler(); + } + if (PlatformUtils.isWebStorm()) { return new TypeScriptConcreteNativeTypesHandler(); } @@ -109,10 +109,11 @@ public static INativeTypesHandler getDefaultNativeTypesHandler(Module module) { public static INativeTypesHandler getNativeTypesHandler(String fileName) { INativeTypesHandler result = null; - if (fileName.endsWith(".kt")) result = new KotlinNativeTypesHandler(); + if (fileName.endsWith(".kt")) result = new KotlinNativeTypesHandler(); if (fileName.endsWith(".java")) result = new JavaNativeTypesHandler(); - if (fileName.endsWith(".dtos.ts")) result = new TypeScriptConcreteNativeTypesHandler(); - if (fileName.endsWith(".dtos.d.ts")) result = new TypeScriptNativeTypesHandler(); + if (fileName.endsWith("dtos.dart")) result = new DartNativeTypesHandler(); + if (fileName.endsWith("dtos.ts")) result = new TypeScriptConcreteNativeTypesHandler(); + if (fileName.endsWith("dtos.d.ts")) result = new TypeScriptNativeTypesHandler(); return result; } } diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/NativeTypesLanguage.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/NativeTypesLanguage.java index c0f5541a..b4b554bf 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/NativeTypesLanguage.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/NativeTypesLanguage.java @@ -6,6 +6,7 @@ public enum NativeTypesLanguage { Java, Kotlin, + Dart, TypeScriptConcrete, TypeScript } diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/UpdateServiceStackUtils.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/UpdateServiceStackUtils.java index 3ac453d8..5764eae6 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/UpdateServiceStackUtils.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/UpdateServiceStackUtils.java @@ -31,25 +31,25 @@ public static void updateServiceStackReference(PsiFile psiFile) { while (scanner.hasNextLine()) { String line = scanner.nextLine(); linesOfCode.add(line); - if(line.startsWith("*/")) break; + if (line.startsWith("*/")) break; } scanner.close(); int startParamsIndex = 0; String baseUrl = null; - for(String item : linesOfCode) { + for (String item : linesOfCode) { startParamsIndex++; - if(item.startsWith("BaseUrl:")) { + if (item.startsWith("BaseUrl:")) { baseUrl = item.split(":",2)[1].trim(); break; } } - if(baseUrl == null) { + if (baseUrl == null) { Notification notification = new Notification("ServiceStackIDEA", "Error Updating Reference", "BaseUrl property not found.", NotificationType.ERROR); Notifications.Bus.notify(notification); return; } - if(!baseUrl.endsWith("/")) { + if (!baseUrl.endsWith("/")) { baseUrl += "/"; } @@ -66,16 +66,16 @@ public static void updateServiceStackReference(PsiFile psiFile) { INativeTypesHandler nativeTypesHandler = IDEAUtils.getNativeTypesHandler(psiFile.getName()); String existingPath = builder.getPath(); - if(existingPath == null || existingPath.equals("/")) { + if (existingPath == null || existingPath.equals("/")) { builder.setPath(combinePath("", nativeTypesHandler.getRelativeTypesUrl())); } else { builder.setPath(combinePath(existingPath, nativeTypesHandler.getRelativeTypesUrl())); } Map options = new HashMap(); - for(int i = startParamsIndex; i < linesOfCode.size(); i++) { + for (int i = startParamsIndex; i < linesOfCode.size(); i++) { String configLine = linesOfCode.get(i); - if(!configLine.startsWith("//") && configLine.contains(":")) { + if (!configLine.startsWith("//") && configLine.contains(":")) { String[] keyVal = configLine.split(":"); options.put(keyVal[0], keyVal[1].trim()); } @@ -86,7 +86,7 @@ public static void updateServiceStackReference(PsiFile psiFile) { int count = 0; // Using URIBuilder with 'addParameter' URL encodes query values.. // Append manually below to avoid issues https://github.com/ServiceStack/ServiceStack.Java/issues/6 - for(Map.Entry option : options.entrySet()) { + for (Map.Entry option : options.entrySet()) { if(count == 0) { serverUrl += "?"; } else { @@ -113,7 +113,7 @@ public static void updateServiceStackReference(PsiFile psiFile) { } String javaCode = javaCodeResponse.toString(); - if(!javaCode.startsWith("/* Options:")) { + if (!javaCode.startsWith("/* Options:")) { Notification notification = new Notification("ServiceStackIDEA", "Error Updating Reference", "Invalid response from provided BaseUrl - " + baseUrl, NotificationType.ERROR); Notifications.Bus.notify(notification); return; diff --git a/src/ServiceStackIDEA/src/main/resources/META-INF/plugin.xml b/src/ServiceStackIDEA/src/main/resources/META-INF/plugin.xml index e690fee0..9e9c502b 100644 --- a/src/ServiceStackIDEA/src/main/resources/META-INF/plugin.xml +++ b/src/ServiceStackIDEA/src/main/resources/META-INF/plugin.xml @@ -2,7 +2,7 @@ net.servicestack.ideaplugin ServiceStack - 1.0.14 + 1.0.15 ServiceStack +
  • 1.0.15 - Add Dart ServiceStack Reference support.
  • 1.0.14 - Fix adding Android dependencies.
  • 1.0.12 - Fix TypeScript dialog defaults to use classes over definitions only.
  • 1.0.11 - Small UI fixes.
  • From c38934aecc6442ab6a1d3b54af4d9bbaa11aebb7 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Mon, 3 Feb 2020 16:14:57 -0500 Subject: [PATCH 093/211] dart ref tweaks --- src/ServiceStackIDEA/.idea/workspace.xml | 15 +++++++-------- .../servicestack/idea/AddServiceStackAction.java | 10 ++++++++-- .../idea/AddServiceStackRefHandler.java | 8 ++++---- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/ServiceStackIDEA/.idea/workspace.xml b/src/ServiceStackIDEA/.idea/workspace.xml index 292ef8ff..8ef985e8 100644 --- a/src/ServiceStackIDEA/.idea/workspace.xml +++ b/src/ServiceStackIDEA/.idea/workspace.xml @@ -5,14 +5,9 @@
    - - - - - - + diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackAction.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackAction.java index 049066ef..1fd05a91 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackAction.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackAction.java @@ -19,6 +19,7 @@ import com.intellij.util.PlatformUtils; import org.jetbrains.annotations.NotNull; +import java.io.File; import java.util.ArrayList; import java.util.List; @@ -155,14 +156,14 @@ public void update(AnActionEvent e) { return; } - if (!(PlatformUtils.isIntelliJ() || isAndroidProject(module))) { + if (!(PlatformUtils.isIntelliJ() || isAndroidProject(module) || isDartProject(module))) { e.getPresentation().setVisible(false); return; } boolean isMavenModule = IDEAPomFileHelper.isMavenModule(module); - if (isAndroidProject(module) || isMavenModule) { + if (isAndroidProject(module) || isMavenModule || isDartProject(module)) { e.getPresentation().setEnabled(true); } else { e.getPresentation().setEnabled(false); @@ -192,6 +193,10 @@ private static boolean isAndroidProject(@NotNull Module module) { return false; } + private static boolean isDartProject(@NotNull Module module) { + return GradleBuildFileHelper.isDartProject(module); + } + static Module getModule(AnActionEvent e) { Module module = e.getData(LangDataKeys.MODULE); if (module == null) { @@ -201,4 +206,5 @@ static Module getModule(AnActionEvent e) { return module; } } + } diff --git a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackRefHandler.java b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackRefHandler.java index 56ac7713..caf2e683 100644 --- a/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackRefHandler.java +++ b/src/ServiceStackIDEA/src/main/java/net/servicestack/idea/AddServiceStackRefHandler.java @@ -55,7 +55,7 @@ public static void handleOk(String addressUrl, String qualifiedPackageName, String dtoPath; try { - dtoPath = getDtoPath(module,qualifiedPackageName,selectedDirectory, fileName,errorMessage); + dtoPath = getDtoPath(module,qualifiedPackageName, selectedDirectory, fileName, errorMessage); } catch (Exception e) { return; } @@ -160,15 +160,15 @@ private static String getDtoPath(Module module, String qualifiedPackageName, Str String fullDtoPath; PsiPackage mainPackage = JavaPsiFacade.getInstance(module.getProject()).findPackage(qualifiedPackageName); - if(mainPackage != null && mainPackage.isValid() && mainPackage.getDirectories().length > 0) { + if (mainPackage != null && mainPackage.isValid() && mainPackage.getDirectories().length > 0) { File file = new File(selectedDirectory); VirtualFile selectedFolder = LocalFileSystem.getInstance().findFileByIoFile(file); - if(selectedFolder == null) { + if (selectedFolder == null) { errorMessage.append("Unable to determine path for DTO file."); throw new FileNotFoundException(); } PsiDirectory rootPackageDir = PsiManager.getInstance(module.getProject()).findDirectory(selectedFolder); - if(rootPackageDir == null) { + if (rootPackageDir == null) { errorMessage.append("Unable to determine path for DTO file."); throw new FileNotFoundException(); } From dfa5399c2e7be6b7f9462f76d703c0e4de875770 Mon Sep 17 00:00:00 2001 From: Darren Reid Date: Tue, 4 Feb 2020 09:14:56 +1100 Subject: [PATCH 094/211] parameterize publish channel --- src/ServiceStackIDEA/build.gradle | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ServiceStackIDEA/build.gradle b/src/ServiceStackIDEA/build.gradle index 459428bf..446d0dd5 100644 --- a/src/ServiceStackIDEA/build.gradle +++ b/src/ServiceStackIDEA/build.gradle @@ -12,13 +12,16 @@ if(System.env.BUILD_NUMBER != null && System.env.SERVICESTACKIDEA_PUBLISH_NIGHTL // Append build number to version for a new nightly build version to be published. version = "${version}.$System.env.BUILD_NUMBER" } - String jbToken; +String publishChannel; if (properties.getProperty("jetbrains.plugins.user", null) == null) { properties.load(project.file('./local.properties').newDataInputStream()) } jbToken = properties.getProperty("jetbrains.plugins.token"); +if (properties.getProperty("jetbrains.plugins.publishChannel", null) != null) { + publishChannel = properties.getProperty("jetbrains.plugins.publishChannel"); +} intellij { version 'IC-14.1.4' @@ -28,6 +31,6 @@ intellij { publishPlugin { token jbToken - channels 'beta' + channels publishChannel } } From cdd7a300a98d62158727d5deff75dfcb332df875 Mon Sep 17 00:00:00 2001 From: Darren Reid Date: Tue, 4 Feb 2020 09:25:09 +1100 Subject: [PATCH 095/211] Update build.gradle --- src/ServiceStackIDEA/build.gradle | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ServiceStackIDEA/build.gradle b/src/ServiceStackIDEA/build.gradle index 446d0dd5..d146e44a 100644 --- a/src/ServiceStackIDEA/build.gradle +++ b/src/ServiceStackIDEA/build.gradle @@ -19,8 +19,9 @@ if (properties.getProperty("jetbrains.plugins.user", null) == null) { properties.load(project.file('./local.properties').newDataInputStream()) } jbToken = properties.getProperty("jetbrains.plugins.token"); -if (properties.getProperty("jetbrains.plugins.publishChannel", null) != null) { - publishChannel = properties.getProperty("jetbrains.plugins.publishChannel"); +publishChannel = properties.getProperty("jetbrains.plugins.publishChannel"); +if (publishChannel == null) { + publishChannel = 'nightly' } intellij { From 87138df935fede5e488ec3903cae12b76f9eb3c4 Mon Sep 17 00:00:00 2001 From: Darren Reid Date: Tue, 4 Feb 2020 09:33:18 +1100 Subject: [PATCH 096/211] Revert --- src/ServiceStackIDEA/build.gradle | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/ServiceStackIDEA/build.gradle b/src/ServiceStackIDEA/build.gradle index d146e44a..459428bf 100644 --- a/src/ServiceStackIDEA/build.gradle +++ b/src/ServiceStackIDEA/build.gradle @@ -12,17 +12,13 @@ if(System.env.BUILD_NUMBER != null && System.env.SERVICESTACKIDEA_PUBLISH_NIGHTL // Append build number to version for a new nightly build version to be published. version = "${version}.$System.env.BUILD_NUMBER" } + String jbToken; -String publishChannel; if (properties.getProperty("jetbrains.plugins.user", null) == null) { properties.load(project.file('./local.properties').newDataInputStream()) } jbToken = properties.getProperty("jetbrains.plugins.token"); -publishChannel = properties.getProperty("jetbrains.plugins.publishChannel"); -if (publishChannel == null) { - publishChannel = 'nightly' -} intellij { version 'IC-14.1.4' @@ -32,6 +28,6 @@ intellij { publishPlugin { token jbToken - channels publishChannel + channels 'beta' } } From c02e4bb03ce9c11d2c3857171bb25449c0620cca Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Tue, 3 Mar 2020 18:06:59 +0800 Subject: [PATCH 097/211] implement get/setBearerToken and setTokenCookie --- .../client/JsonServiceClient.java | 127 +++++++++++------- .../servicestack/client/ServiceClient.java | 3 + .../client/JsonServiceClient.java | 127 +++++++++++------- .../servicestack/client/ServiceClient.java | 3 + 4 files changed, 164 insertions(+), 96 deletions(-) diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/JsonServiceClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/JsonServiceClient.java index 059f00a4..38e34408 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/JsonServiceClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/JsonServiceClient.java @@ -20,6 +20,8 @@ import java.net.CookieManager; import java.net.HttpCookie; import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.Charset; @@ -30,11 +32,13 @@ public class JsonServiceClient implements ServiceClient { static Charset UTF8 = Charset.forName("UTF-8"); String baseUrl; + URI baseUri; String replyUrl; boolean alwaysSendBasicAuthHeaders; String userName; String password; + String bearerToken; Integer timeoutMs; public ConnectionFilter RequestFilter; @@ -47,8 +51,16 @@ public class JsonServiceClient implements ServiceClient { Gson gson; public JsonServiceClient(String baseUrl) { + this(baseUrl, true); + } + public JsonServiceClient(String baseUrl, boolean initCookies) { setBaseUrl(baseUrl); + if (initCookies) { + initCookieHandler(); + } + } + public void initCookieHandler() { //Automatically populate response cookies if (CookieHandler.getDefault() == null){ CookieHandler.setDefault(new CookieManager()); @@ -57,6 +69,11 @@ public JsonServiceClient(String baseUrl) { public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/"; + try { + this.baseUri = new URI(this.baseUrl); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } this.replyUrl = this.baseUrl + "json/reply/"; } @@ -66,13 +83,13 @@ public void setTimeout(int timeoutMs) { public GsonBuilder getGsonBuilder() { return new GsonBuilder() - .registerTypeAdapterFactory(JsonSerializers.getCaseInsensitiveEnumTypeAdapterFactory()) - .registerTypeAdapter(Date.class, JsonSerializers.getDateSerializer()) - .registerTypeAdapter(Date.class, JsonSerializers.getDateDeserializer()) - .registerTypeAdapter(TimeSpan.class, JsonSerializers.getTimeSpanSerializer()) - .registerTypeAdapter(TimeSpan.class, JsonSerializers.getTimeSpanDeserializer()) - .registerTypeAdapter(UUID.class, JsonSerializers.getGuidSerializer()) - .registerTypeAdapter(UUID.class, JsonSerializers.getGuidDeserializer()); + .registerTypeAdapterFactory(JsonSerializers.getCaseInsensitiveEnumTypeAdapterFactory()) + .registerTypeAdapter(Date.class, JsonSerializers.getDateSerializer()) + .registerTypeAdapter(Date.class, JsonSerializers.getDateDeserializer()) + .registerTypeAdapter(TimeSpan.class, JsonSerializers.getTimeSpanSerializer()) + .registerTypeAdapter(TimeSpan.class, JsonSerializers.getTimeSpanDeserializer()) + .registerTypeAdapter(UUID.class, JsonSerializers.getGuidSerializer()) + .registerTypeAdapter(UUID.class, JsonSerializers.getGuidDeserializer()); } public Gson getGson() { @@ -137,10 +154,10 @@ public String createUrl(Object requestDto, Map query){ } public HttpURLConnection createRequest(String requestUrl, String httpMethod, byte[] requestBody, String requestType) { - return createRequest(requestUrl, httpMethod, requestBody, requestType, false); - + return createRequest(requestUrl, httpMethod, requestBody, requestType, false); + } - + public HttpURLConnection createRequest(String requestUrl, String httpMethod, byte[] requestBody, String requestType, Boolean forceAuthentication) { try { URL url = new URL(requestUrl); @@ -159,8 +176,12 @@ public HttpURLConnection createRequest(String requestUrl, String httpMethod, byt req.setRequestProperty(HttpHeaders.ContentType, requestType); } - if (forceAuthentication || alwaysSendBasicAuthHeaders) { - addBasicAuth(req, userName, password); + if (bearerToken != null) { + req.setRequestProperty(HttpHeaders.Authorization, "Bearer " + bearerToken); + req.setRequestProperty("X-Auth", "Bearer"); // HttpURLConnection doesn't allow re-reading Authorization Header + } else if (forceAuthentication || alwaysSendBasicAuthHeaders) { + req.setRequestProperty(HttpHeaders.Authorization, "Basic " + Utils.toBase64String(userName + ":" + password)); + req.setRequestProperty("X-Auth", "Basic"); // HttpURLConnection doesn't allow re-reading Authorization Header } if (RequestFilter != null) { @@ -187,18 +208,12 @@ public HttpURLConnection createRequest(String requestUrl, String httpMethod, byt } } - private static void addBasicAuth(HttpURLConnection req, String userName, String password) { - req.setRequestProperty(HttpHeaders.Authorization, - "Basic " + Utils.toBase64String(userName + ":" + password)); - req.setRequestProperty("X-Auth", "Basic"); // HttpURLConnection doesn't allow re-reading Authorization Header - } - private static boolean shouldAuthenticate(HttpURLConnection req, String userName, String password){ try { return req.getResponseCode() == 401 - && req.getRequestProperty("X-Auth") == null //only auth if auth never attempted - && userName != null - && password != null; + && req.getRequestProperty("X-Auth") == null //only auth if auth never attempted + && userName != null + && password != null; } catch (IOException e) { return false; } @@ -211,8 +226,8 @@ public static RuntimeException createException(HttpURLConnection res, int respon InputStream errorStream = res.getErrorStream(); String responseBody = errorStream != null - ? Utils.readToEnd(errorStream, UTF8.name()) - : null; + ? Utils.readToEnd(errorStream, UTF8.name()) + : null; webEx = new WebServiceException(responseCode, res.getResponseMessage(), responseBody); @@ -243,16 +258,16 @@ public static RuntimeException createException(HttpURLConnection res, int respon public static String GetSendMethod(Object request) { return request instanceof IGet ? - HttpMethods.Get - : request instanceof IPost ? - HttpMethods.Post - : request instanceof IPut ? - HttpMethods.Put - : request instanceof IDelete ? - HttpMethods.Delete - : request instanceof IPatch ? - HttpMethods.Patch : - HttpMethods.Post; + HttpMethods.Get + : request instanceof IPost ? + HttpMethods.Post + : request instanceof IPut ? + HttpMethods.Put + : request instanceof IDelete ? + HttpMethods.Delete + : request instanceof IPatch ? + HttpMethods.Patch : + HttpMethods.Post; } public static boolean hasRequestBody(String httpMethod) @@ -278,6 +293,21 @@ public void setAlwaysSendBasicAuthHeaders(boolean value) { this.alwaysSendBasicAuthHeaders = value; } + @Override + public void setBearerToken(String bearerToken) { + this.bearerToken = bearerToken; + } + + @Override + public String getBearerToken() { + return bearerToken; + } + + @Override + public void setTokenCookie(String value) { + setCookie("ss-tok", value, (long) (365 * 24 * 60 * 60)); //1 year + } + @Override public void setCredentials(String userName, String password) { this.userName = userName; @@ -303,7 +333,7 @@ public TResponse send(IReturn request) { public void send(IReturnVoid request) { String httpMethod = GetSendMethod(request); send(Utils.combinePath(replyUrl, typeName(request)), httpMethod, request, - IReturnVoid.class); + IReturnVoid.class); } public TResponse send(String url, String httpMethod, Object responseClass) { @@ -343,7 +373,7 @@ public TResponse send(String requestUrl, String httpMethod, byte[] r if (shouldAuthenticate(req, userName, password)){ req.disconnect(); req = createRequest(requestUrl, httpMethod, requestBody, requestType, true); - + success = req.getResponseCode() < 400; } @@ -384,16 +414,16 @@ public TResponse send(String requestUrl, String httpMethod, byte[] r Log.d(json); TResponse response = resClass != null - ? (TResponse) getGson().fromJson(json, resClass) - : (TResponse) getGson().fromJson(json, resType); + ? (TResponse) getGson().fromJson(json, resClass) + : (TResponse) getGson().fromJson(json, resType); return response; } else { BufferedReader reader = new BufferedReader(new InputStreamReader(is)); TResponse response = resClass != null - ? (TResponse) getGson().fromJson(reader, resClass) - : (TResponse) getGson().fromJson(reader, resType); + ? (TResponse) getGson().fromJson(reader, resClass) + : (TResponse) getGson().fromJson(reader, resType); Utils.closeQuietly(reader); return response; @@ -413,9 +443,9 @@ static String typeName(Object o){ private String resolveUrl(String relativeOrAbsoluteUrl) { return relativeOrAbsoluteUrl.startsWith("http:") - || relativeOrAbsoluteUrl.startsWith("https:") - ? relativeOrAbsoluteUrl - : Utils.combinePath(baseUrl, relativeOrAbsoluteUrl); + || relativeOrAbsoluteUrl.startsWith("https:") + ? relativeOrAbsoluteUrl + : Utils.combinePath(baseUrl, relativeOrAbsoluteUrl); } @Override @@ -451,8 +481,8 @@ public HttpURLConnection get(String path) { @Override public TResponse post(IReturn request) { return send( - Utils.combinePath(replyUrl, typeName(request)), HttpMethods.Post, request, - request.getResponseType()); + Utils.combinePath(replyUrl, typeName(request)), HttpMethods.Post, request, + request.getResponseType()); } @Override @@ -488,14 +518,14 @@ public HttpURLConnection post(String path, byte[] requestBody, String contentTyp @Override public TResponse put(IReturn request) { return send( - Utils.combinePath(replyUrl, typeName(request)), HttpMethods.Put, request, - request.getResponseType()); + Utils.combinePath(replyUrl, typeName(request)), HttpMethods.Put, request, + request.getResponseType()); } @Override public void put(IReturnVoid request) { send(Utils.combinePath(replyUrl, typeName(request)), HttpMethods.Put, request, - IReturnVoid.class); + IReturnVoid.class); } @Override @@ -562,10 +592,11 @@ public void setCookie(String name, String value) { public void setCookie(String name, String value, Long expiresInSecs) { CookieManager cookieManager = (CookieManager) CookieHandler.getDefault(); HttpCookie cookie = new HttpCookie(name, value); + cookie.setVersion(0); // Required otherwise it quotes values https://stackoverflow.com/a/20204076/85785 if (expiresInSecs != null){ cookie.setMaxAge(expiresInSecs); } - cookieManager.getCookieStore().getCookies().add(cookie); + cookieManager.getCookieStore().add(baseUri, cookie); } @Override diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/client/ServiceClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/client/ServiceClient.java index 9a4aadcc..1272b2b3 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/client/ServiceClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/client/ServiceClient.java @@ -9,6 +9,9 @@ public interface ServiceClient { boolean getAlwaysSendBasicAuthHeaders(); + void setBearerToken(String value); + String getBearerToken(); + void setTokenCookie(String value); void setAlwaysSendBasicAuthHeaders(boolean value); void setCredentials(String userName, String password); diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/JsonServiceClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/JsonServiceClient.java index 059f00a4..38e34408 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/JsonServiceClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/JsonServiceClient.java @@ -20,6 +20,8 @@ import java.net.CookieManager; import java.net.HttpCookie; import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.Charset; @@ -30,11 +32,13 @@ public class JsonServiceClient implements ServiceClient { static Charset UTF8 = Charset.forName("UTF-8"); String baseUrl; + URI baseUri; String replyUrl; boolean alwaysSendBasicAuthHeaders; String userName; String password; + String bearerToken; Integer timeoutMs; public ConnectionFilter RequestFilter; @@ -47,8 +51,16 @@ public class JsonServiceClient implements ServiceClient { Gson gson; public JsonServiceClient(String baseUrl) { + this(baseUrl, true); + } + public JsonServiceClient(String baseUrl, boolean initCookies) { setBaseUrl(baseUrl); + if (initCookies) { + initCookieHandler(); + } + } + public void initCookieHandler() { //Automatically populate response cookies if (CookieHandler.getDefault() == null){ CookieHandler.setDefault(new CookieManager()); @@ -57,6 +69,11 @@ public JsonServiceClient(String baseUrl) { public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/"; + try { + this.baseUri = new URI(this.baseUrl); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } this.replyUrl = this.baseUrl + "json/reply/"; } @@ -66,13 +83,13 @@ public void setTimeout(int timeoutMs) { public GsonBuilder getGsonBuilder() { return new GsonBuilder() - .registerTypeAdapterFactory(JsonSerializers.getCaseInsensitiveEnumTypeAdapterFactory()) - .registerTypeAdapter(Date.class, JsonSerializers.getDateSerializer()) - .registerTypeAdapter(Date.class, JsonSerializers.getDateDeserializer()) - .registerTypeAdapter(TimeSpan.class, JsonSerializers.getTimeSpanSerializer()) - .registerTypeAdapter(TimeSpan.class, JsonSerializers.getTimeSpanDeserializer()) - .registerTypeAdapter(UUID.class, JsonSerializers.getGuidSerializer()) - .registerTypeAdapter(UUID.class, JsonSerializers.getGuidDeserializer()); + .registerTypeAdapterFactory(JsonSerializers.getCaseInsensitiveEnumTypeAdapterFactory()) + .registerTypeAdapter(Date.class, JsonSerializers.getDateSerializer()) + .registerTypeAdapter(Date.class, JsonSerializers.getDateDeserializer()) + .registerTypeAdapter(TimeSpan.class, JsonSerializers.getTimeSpanSerializer()) + .registerTypeAdapter(TimeSpan.class, JsonSerializers.getTimeSpanDeserializer()) + .registerTypeAdapter(UUID.class, JsonSerializers.getGuidSerializer()) + .registerTypeAdapter(UUID.class, JsonSerializers.getGuidDeserializer()); } public Gson getGson() { @@ -137,10 +154,10 @@ public String createUrl(Object requestDto, Map query){ } public HttpURLConnection createRequest(String requestUrl, String httpMethod, byte[] requestBody, String requestType) { - return createRequest(requestUrl, httpMethod, requestBody, requestType, false); - + return createRequest(requestUrl, httpMethod, requestBody, requestType, false); + } - + public HttpURLConnection createRequest(String requestUrl, String httpMethod, byte[] requestBody, String requestType, Boolean forceAuthentication) { try { URL url = new URL(requestUrl); @@ -159,8 +176,12 @@ public HttpURLConnection createRequest(String requestUrl, String httpMethod, byt req.setRequestProperty(HttpHeaders.ContentType, requestType); } - if (forceAuthentication || alwaysSendBasicAuthHeaders) { - addBasicAuth(req, userName, password); + if (bearerToken != null) { + req.setRequestProperty(HttpHeaders.Authorization, "Bearer " + bearerToken); + req.setRequestProperty("X-Auth", "Bearer"); // HttpURLConnection doesn't allow re-reading Authorization Header + } else if (forceAuthentication || alwaysSendBasicAuthHeaders) { + req.setRequestProperty(HttpHeaders.Authorization, "Basic " + Utils.toBase64String(userName + ":" + password)); + req.setRequestProperty("X-Auth", "Basic"); // HttpURLConnection doesn't allow re-reading Authorization Header } if (RequestFilter != null) { @@ -187,18 +208,12 @@ public HttpURLConnection createRequest(String requestUrl, String httpMethod, byt } } - private static void addBasicAuth(HttpURLConnection req, String userName, String password) { - req.setRequestProperty(HttpHeaders.Authorization, - "Basic " + Utils.toBase64String(userName + ":" + password)); - req.setRequestProperty("X-Auth", "Basic"); // HttpURLConnection doesn't allow re-reading Authorization Header - } - private static boolean shouldAuthenticate(HttpURLConnection req, String userName, String password){ try { return req.getResponseCode() == 401 - && req.getRequestProperty("X-Auth") == null //only auth if auth never attempted - && userName != null - && password != null; + && req.getRequestProperty("X-Auth") == null //only auth if auth never attempted + && userName != null + && password != null; } catch (IOException e) { return false; } @@ -211,8 +226,8 @@ public static RuntimeException createException(HttpURLConnection res, int respon InputStream errorStream = res.getErrorStream(); String responseBody = errorStream != null - ? Utils.readToEnd(errorStream, UTF8.name()) - : null; + ? Utils.readToEnd(errorStream, UTF8.name()) + : null; webEx = new WebServiceException(responseCode, res.getResponseMessage(), responseBody); @@ -243,16 +258,16 @@ public static RuntimeException createException(HttpURLConnection res, int respon public static String GetSendMethod(Object request) { return request instanceof IGet ? - HttpMethods.Get - : request instanceof IPost ? - HttpMethods.Post - : request instanceof IPut ? - HttpMethods.Put - : request instanceof IDelete ? - HttpMethods.Delete - : request instanceof IPatch ? - HttpMethods.Patch : - HttpMethods.Post; + HttpMethods.Get + : request instanceof IPost ? + HttpMethods.Post + : request instanceof IPut ? + HttpMethods.Put + : request instanceof IDelete ? + HttpMethods.Delete + : request instanceof IPatch ? + HttpMethods.Patch : + HttpMethods.Post; } public static boolean hasRequestBody(String httpMethod) @@ -278,6 +293,21 @@ public void setAlwaysSendBasicAuthHeaders(boolean value) { this.alwaysSendBasicAuthHeaders = value; } + @Override + public void setBearerToken(String bearerToken) { + this.bearerToken = bearerToken; + } + + @Override + public String getBearerToken() { + return bearerToken; + } + + @Override + public void setTokenCookie(String value) { + setCookie("ss-tok", value, (long) (365 * 24 * 60 * 60)); //1 year + } + @Override public void setCredentials(String userName, String password) { this.userName = userName; @@ -303,7 +333,7 @@ public TResponse send(IReturn request) { public void send(IReturnVoid request) { String httpMethod = GetSendMethod(request); send(Utils.combinePath(replyUrl, typeName(request)), httpMethod, request, - IReturnVoid.class); + IReturnVoid.class); } public TResponse send(String url, String httpMethod, Object responseClass) { @@ -343,7 +373,7 @@ public TResponse send(String requestUrl, String httpMethod, byte[] r if (shouldAuthenticate(req, userName, password)){ req.disconnect(); req = createRequest(requestUrl, httpMethod, requestBody, requestType, true); - + success = req.getResponseCode() < 400; } @@ -384,16 +414,16 @@ public TResponse send(String requestUrl, String httpMethod, byte[] r Log.d(json); TResponse response = resClass != null - ? (TResponse) getGson().fromJson(json, resClass) - : (TResponse) getGson().fromJson(json, resType); + ? (TResponse) getGson().fromJson(json, resClass) + : (TResponse) getGson().fromJson(json, resType); return response; } else { BufferedReader reader = new BufferedReader(new InputStreamReader(is)); TResponse response = resClass != null - ? (TResponse) getGson().fromJson(reader, resClass) - : (TResponse) getGson().fromJson(reader, resType); + ? (TResponse) getGson().fromJson(reader, resClass) + : (TResponse) getGson().fromJson(reader, resType); Utils.closeQuietly(reader); return response; @@ -413,9 +443,9 @@ static String typeName(Object o){ private String resolveUrl(String relativeOrAbsoluteUrl) { return relativeOrAbsoluteUrl.startsWith("http:") - || relativeOrAbsoluteUrl.startsWith("https:") - ? relativeOrAbsoluteUrl - : Utils.combinePath(baseUrl, relativeOrAbsoluteUrl); + || relativeOrAbsoluteUrl.startsWith("https:") + ? relativeOrAbsoluteUrl + : Utils.combinePath(baseUrl, relativeOrAbsoluteUrl); } @Override @@ -451,8 +481,8 @@ public HttpURLConnection get(String path) { @Override public TResponse post(IReturn request) { return send( - Utils.combinePath(replyUrl, typeName(request)), HttpMethods.Post, request, - request.getResponseType()); + Utils.combinePath(replyUrl, typeName(request)), HttpMethods.Post, request, + request.getResponseType()); } @Override @@ -488,14 +518,14 @@ public HttpURLConnection post(String path, byte[] requestBody, String contentTyp @Override public TResponse put(IReturn request) { return send( - Utils.combinePath(replyUrl, typeName(request)), HttpMethods.Put, request, - request.getResponseType()); + Utils.combinePath(replyUrl, typeName(request)), HttpMethods.Put, request, + request.getResponseType()); } @Override public void put(IReturnVoid request) { send(Utils.combinePath(replyUrl, typeName(request)), HttpMethods.Put, request, - IReturnVoid.class); + IReturnVoid.class); } @Override @@ -562,10 +592,11 @@ public void setCookie(String name, String value) { public void setCookie(String name, String value, Long expiresInSecs) { CookieManager cookieManager = (CookieManager) CookieHandler.getDefault(); HttpCookie cookie = new HttpCookie(name, value); + cookie.setVersion(0); // Required otherwise it quotes values https://stackoverflow.com/a/20204076/85785 if (expiresInSecs != null){ cookie.setMaxAge(expiresInSecs); } - cookieManager.getCookieStore().getCookies().add(cookie); + cookieManager.getCookieStore().add(baseUri, cookie); } @Override diff --git a/src/AndroidClient/client/src/main/java/net/servicestack/client/ServiceClient.java b/src/AndroidClient/client/src/main/java/net/servicestack/client/ServiceClient.java index 9a4aadcc..1272b2b3 100644 --- a/src/AndroidClient/client/src/main/java/net/servicestack/client/ServiceClient.java +++ b/src/AndroidClient/client/src/main/java/net/servicestack/client/ServiceClient.java @@ -9,6 +9,9 @@ public interface ServiceClient { boolean getAlwaysSendBasicAuthHeaders(); + void setBearerToken(String value); + String getBearerToken(); + void setTokenCookie(String value); void setAlwaysSendBasicAuthHeaders(boolean value); void setCredentials(String userName, String password); From ed529a5bb77adf59b41a41a7d6dbe50e73c77cc6 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Tue, 3 Mar 2020 18:08:04 +0800 Subject: [PATCH 098/211] Add ability to store persistent cookies if configured with an android Context --- .../android/AndroidServiceClient.java | 32 +- .../cookies/SerializableCookie.java | 49 ++ .../cookies/SerializableCookieStore.java | 464 ++++++++++++++++++ 3 files changed, 543 insertions(+), 2 deletions(-) create mode 100644 src/AndroidClient/android/src/main/java/net/servicestack/cookies/SerializableCookie.java create mode 100644 src/AndroidClient/android/src/main/java/net/servicestack/cookies/SerializableCookieStore.java diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServiceClient.java b/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServiceClient.java index 1dbd7815..9d72c2ab 100644 --- a/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServiceClient.java +++ b/src/AndroidClient/android/src/main/java/net/servicestack/android/AndroidServiceClient.java @@ -3,30 +3,58 @@ package net.servicestack.android; +import android.content.Context; import android.os.AsyncTask; -import net.servicestack.client.AsyncComplete; import net.servicestack.client.AsyncError; import net.servicestack.client.AsyncResult; import net.servicestack.client.AsyncResultVoid; import net.servicestack.client.AsyncServiceClient; +import net.servicestack.client.AsyncSuccess; import net.servicestack.client.AsyncSuccessVoid; import net.servicestack.client.IReturn; import net.servicestack.client.IReturnVoid; import net.servicestack.client.JsonServiceClient; -import net.servicestack.client.AsyncSuccess; import net.servicestack.client.Utils; +import net.servicestack.cookies.SerializableCookieStore; import java.lang.reflect.Type; +import java.net.CookieHandler; +import java.net.CookieManager; +import java.net.CookiePolicy; import java.net.HttpURLConnection; import java.util.Map; public class AndroidServiceClient extends JsonServiceClient implements AsyncServiceClient { + Context context; + public AndroidServiceClient(String baseUrl) { super(baseUrl); } + public AndroidServiceClient(String baseUrl, Context context) { + super(baseUrl, false); + this.context = context; + this.initCookieHandler(); + } + + @Override + public void initCookieHandler() { + //Automatically populate response cookies + if (CookieHandler.getDefault() == null) { + if (this.context != null) { + SerializableCookieStore cookieStore = new SerializableCookieStore(context); + CookieManager cookieManager = new CookieManager(cookieStore, CookiePolicy.ACCEPT_ALL); + CookieHandler.setDefault(cookieManager); + } else { + //Doesn't support getCookieStore() throws UnsupportedOperationException + CookieManager cookieManager = new CookieManager(null, CookiePolicy.ACCEPT_ALL); + CookieHandler.setDefault(cookieManager); + } + } + } + // Override to customize execution of AsyncTask public void execTask(AsyncTask asyncTask, T... request){ asyncTask.execute(request); diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/cookies/SerializableCookie.java b/src/AndroidClient/android/src/main/java/net/servicestack/cookies/SerializableCookie.java new file mode 100644 index 00000000..3f8b1117 --- /dev/null +++ b/src/AndroidClient/android/src/main/java/net/servicestack/cookies/SerializableCookie.java @@ -0,0 +1,49 @@ +package net.servicestack.cookies; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.net.HttpCookie; + +//FROM: https://gist.github.com/manishk3008/2a2373c6c155a5df6326 +public class SerializableCookie implements Serializable { + private HttpCookie cookie; + private static final long serialVersionUID = 2532101328282342578L; + public SerializableCookie(HttpCookie cookie) { + this.cookie = cookie; + } + + public HttpCookie getCookie() { + return cookie; + } + + private void writeObject(ObjectOutputStream out) throws IOException { + out.writeObject(cookie.getName()); + out.writeObject(cookie.getValue()); + out.writeObject(cookie.getComment()); + out.writeObject(cookie.getCommentURL()); + out.writeBoolean(cookie.getDiscard()); + out.writeObject(cookie.getDomain()); + out.writeLong(cookie.getMaxAge()); + out.writeObject(cookie.getPath()); + out.writeObject(cookie.getPortlist()); + out.writeBoolean(cookie.getSecure()); + out.writeInt(cookie.getVersion()); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + String name = (String) in.readObject(); + String value = (String) in.readObject(); + cookie = new HttpCookie(name, value); + cookie.setComment((String) in.readObject()); + cookie.setCommentURL((String) in.readObject()); + cookie.setDiscard(in.readBoolean()); + cookie.setDomain((String) in.readObject()); + cookie.setMaxAge(in.readLong()); + cookie.setPath((String) in.readObject()); + cookie.setPortlist((String) in.readObject()); + cookie.setSecure(in.readBoolean()); + cookie.setVersion(in.readInt()); + } +} diff --git a/src/AndroidClient/android/src/main/java/net/servicestack/cookies/SerializableCookieStore.java b/src/AndroidClient/android/src/main/java/net/servicestack/cookies/SerializableCookieStore.java new file mode 100644 index 00000000..2a68a8ae --- /dev/null +++ b/src/AndroidClient/android/src/main/java/net/servicestack/cookies/SerializableCookieStore.java @@ -0,0 +1,464 @@ +package net.servicestack.cookies; + +import android.content.Context; +import android.content.SharedPreferences; +import android.text.TextUtils; +import android.util.Log; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.CookieStore; +import java.net.HttpCookie; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +//FROM: https://gist.github.com/manishk3008/2a2373c6c155a5df6326 +public class SerializableCookieStore implements CookieStore { + private static final String LOG_TAG = "SerializableCookieStore"; + private static final String COOKIE_PREFS = "net.servicestack.cookieprefs"; + private static final String COOKIE_DOMAINS_STORE = "net.servicestack.CookieStore.domain"; + private static final String COOKIE_DOMAIN_PREFIX = "net.servicestack.CookieStore.domain_"; + private static final String COOKIE_NAME_PREFIX = "net.servicestack.CookieStore.cookie_"; + + /*This map here will store all domain to cookies bindings*/ + private final CookieMap map; + private final SharedPreferences cookiePrefs; + + /** + * Construct a persistent cookie store. + * @param context Context to attach cookie store to + */ + public SerializableCookieStore(Context context) { + cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0); + map = new CookieMap(); + + // Load any previously stored domains into the store + String storedCookieDomains = cookiePrefs.getString(COOKIE_DOMAINS_STORE, null); + if (storedCookieDomains != null) { + String[] storedCookieDomainsArray = TextUtils.split(storedCookieDomains, ","); + //split this domains and get cookie names stored for each domain + for (String domain : storedCookieDomainsArray) { + String storedCookiesNames = cookiePrefs.getString(COOKIE_DOMAIN_PREFIX + domain,null); + //so now we have these cookie names + if (storedCookiesNames != null) { + //split these cookie names and get serialized cookie stored + String[] storedCookieNamesArray = TextUtils.split(storedCookiesNames, ","); + if (storedCookieNamesArray != null) { + //in this list we store all cookies under one URI + List cookies = new ArrayList<>(); + for (String cookieName : storedCookieNamesArray) { + String encCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + domain + cookieName, null); + //now we deserialize this cookie and get HttpCookie out of it and pass it to List + if (encCookie != null) + cookies.add(decodeCookie(encCookie)); + } + map.put(URI.create(domain), cookies); + } + } + } + } + } + + public synchronized void add(URI uri, HttpCookie cookie) { + if (cookie == null) { + throw new NullPointerException("cookie == null"); + } + + uri = cookiesUri(uri); + List cookies = map.get(uri); + if (cookies == null) { + cookies = new ArrayList(); + map.put(uri, cookies); + } else { + cookies.remove(cookie); + } + cookies.add(cookie); + + // Save cookie into persistent store + SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); + prefsWriter.putString(COOKIE_DOMAINS_STORE, TextUtils.join(",", map.keySet())); + + Set names = new HashSet(); + for (HttpCookie cookie2 : cookies) { + names.add(cookie2.getName()); + prefsWriter.putString(COOKIE_NAME_PREFIX + uri + cookie2.getName(), + encodeCookie(new SerializableCookie(cookie2))); + } + prefsWriter.putString(COOKIE_DOMAIN_PREFIX + uri, TextUtils.join(",", names)); + + prefsWriter.commit(); + } + + public synchronized List get(URI uri) { + if (uri == null) { + throw new NullPointerException("uri == null"); + } + + List result = new ArrayList(); + // get cookies associated with given URI. If none, returns an empty list + List cookiesForUri = map.get(uri); + if (cookiesForUri != null) { + for (Iterator i = cookiesForUri.iterator(); i.hasNext();) { + HttpCookie cookie = i.next(); + if (cookie.hasExpired()) { + i.remove(); // remove expired cookies + } else { + result.add(cookie); + } + } + } + // get all cookies that domain matches the URI + for (Map.Entry> entry : map.entrySet()) { + if (uri.equals(entry.getKey())) { + continue; // skip the given URI; we've already handled it + } + List entryCookies = entry.getValue(); + for (Iterator i = entryCookies.iterator(); i.hasNext();) { + HttpCookie cookie = i.next(); + if (!HttpCookie.domainMatches(cookie.getDomain(), uri.getHost())) { + continue; + } + if (cookie.hasExpired()) { + i.remove(); // remove expired cookies + } else if (!result.contains(cookie)) { + result.add(cookie); + } + } + } + return Collections.unmodifiableList(result); + } + + public synchronized List getCookies() { + List result = new ArrayList(); + for (List list : map.values()) { + for (Iterator i = list.iterator(); i.hasNext();) { + HttpCookie cookie = i.next(); + if (cookie.hasExpired()) { + i.remove(); // remove expired cookies + } else if (!result.contains(cookie)) { + result.add(cookie); + } + } + } + return Collections.unmodifiableList(result); + } + + public synchronized List getURIs() { + List result = new ArrayList(map.getAllURIs()); + result.remove(null); // sigh + return Collections.unmodifiableList(result); + } + + public synchronized boolean remove(URI uri, HttpCookie cookie) { + if (cookie == null) { + throw new NullPointerException("cookie == null"); + } + + if (map.removeCookie(uri, cookie)) { + SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); + prefsWriter.putString(COOKIE_DOMAIN_PREFIX + uri, + TextUtils.join(",", map.getAllCookieNames(uri))); + prefsWriter.remove(COOKIE_NAME_PREFIX + uri + cookie.getName()); + prefsWriter.apply(); + return true; + } + return false; + } + + public synchronized boolean removeAll() { + // Clear cookies from persistent store + SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); + prefsWriter.clear(); + prefsWriter.commit(); + + // Clear cookies from local store + boolean result = !map.isEmpty(); + map.clear(); + return result; + } + + /** + * Serializes HttpCookie object into String + * + * @param cookie + * cookie to be encoded, can be null + * @return cookie encoded as String + */ + protected String encodeCookie(SerializableCookie cookie) { + if (cookie == null) + return null; + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + try { + ObjectOutputStream outputStream = new ObjectOutputStream(os); + outputStream.writeObject(cookie); + } catch (IOException e) { + Log.e(LOG_TAG, "IOException in encodeCookie", e); + return null; + } + + return byteArrayToHexString(os.toByteArray()); + } + + /** + * Returns HttpCookie decoded from cookie string + * + * @param cookieString + * string of cookie as returned from http request + * @return decoded cookie or null if exception occured + */ + protected HttpCookie decodeCookie(String cookieString) { + byte[] bytes = hexStringToByteArray(cookieString); + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); + + HttpCookie cookie = null; + try { + ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); + cookie = ((SerializableCookie) objectInputStream.readObject()).getCookie(); + } catch (IOException e) { + Log.e(LOG_TAG, "IOException in decodeCookie", e); + } catch (ClassNotFoundException e) { + Log.e(LOG_TAG, "ClassNotFoundException in decodeCookie", e); + } + + return cookie; + } + + /** + * Using some super basic byte array <-> hex conversions so we don't + * have to rely on any large Base64 libraries. Can be overridden if you + * like! + * + * @param bytes + * byte array to be converted + * @return string containing hex values + */ + protected String byteArrayToHexString(byte[] bytes) { + StringBuilder sb = new StringBuilder(bytes.length * 2); + for (byte element : bytes) { + int v = element & 0xff; + if (v < 16) { + sb.append('0'); + } + sb.append(Integer.toHexString(v)); + } + return sb.toString().toUpperCase(Locale.US); + } + + /** + * Converts hex values from strings to byte arra + * + * @param hexString + * string of hex-encoded values + * @return decoded byte array + */ + protected byte[] hexStringToByteArray(String hexString) { + int len = hexString.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character + .digit(hexString.charAt(i + 1), 16)); + } + return data; + } + /** + * Utility function to male sure that every time you get consistent URI + * @param uri + * @return + */ + private URI cookiesUri(URI uri) { + if (uri == null) { + return null; + } + try { + return new URI(uri.getScheme(), uri.getHost(), null, null); + } catch (URISyntaxException e) { + return uri; + } + } + /** + * A implementation of {@link Map} for utility class for storing URL cookie map + * @author Manish + * + */ + private class CookieMap implements Map> { + + private final Map> map; + + /** + * + */ + public CookieMap() { + map = new HashMap>(); + } + + /* + * (non-Javadoc) + * + * @see java.util.Map#clear() + */ + @Override + public void clear() { + map.clear(); + } + + /* + * (non-Javadoc) + * + * @see java.util.Map#containsKey(java.lang.Object) + */ + @Override + public boolean containsKey(Object key) { + return map.containsKey(key); + } + + /* + * (non-Javadoc) + * + * @see java.util.Map#containsValue(java.lang.Object) + */ + @Override + public boolean containsValue(Object value) { + return map.containsValue(value); + } + + /* + * (non-Javadoc) + * + * @see java.util.Map#entrySet() + */ + @Override + public Set>> entrySet() { + return map.entrySet(); + } + + /* + * (non-Javadoc) + * + * @see java.util.Map#get(java.lang.Object) + */ + @Override + public List get(Object key) { + return map.get(key); + } + + /* + * (non-Javadoc) + * + * @see java.util.Map#isEmpty() + */ + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + /* + * (non-Javadoc) + * + * @see java.util.Map#keySet() + */ + @Override + public Set keySet() { + return map.keySet(); + } + + /* + * (non-Javadoc) + * + * @see java.util.Map#put(java.lang.Object, java.lang.Object) + */ + @Override + public List put(URI key, List value) { + return map.put(key, value); + } + + /* + * (non-Javadoc) + * + * @see java.util.Map#putAll(java.util.Map) + */ + @Override + public void putAll(Map> map) { + this.map.putAll(map); + } + + /* + * (non-Javadoc) + * + * @see java.util.Map#remove(java.lang.Object) + */ + @Override + public List remove(Object key) { + return map.remove(key); + } + + /* + * (non-Javadoc) + * + * @see java.util.Map#size() + */ + @Override + public int size() { + return map.size(); + } + + /* + * (non-Javadoc) + * + * @see java.util.Map#values() + */ + @Override + public Collection> values() { + return map.values(); + } + + /** + * List all URIs for which cookies are stored in map + * @return + */ + public Collection getAllURIs() { + return map.keySet(); + } + + /** + * Get all cookies names stored for given URI + * @param uri + * @return + */ + public Collection getAllCookieNames(URI uri) { + List cookies = map.get(uri); + Set cookieNames = new HashSet(); + for (HttpCookie cookie : cookies) { + cookieNames.add(cookie.getName()); + } + return cookieNames; + } + + /** + * Removes requested {@link HttpCookie} {@code httpCookie} from given {@code uri} value + * @param uri + * @param httpCookie + * @return + */ + public boolean removeCookie(URI uri, HttpCookie httpCookie) { + if (map.containsKey(uri)) { + return map.get(uri).remove(httpCookie); + } else { + return false; + } + } + } +} From b95c5b03e98b2b51e4166f9ea2d43594e8d5c9ff Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Tue, 3 Mar 2020 18:08:19 +0800 Subject: [PATCH 099/211] Add cookie test in Android App --- .../net/androidclient/MainActivity.java | 35 ++ .../net/androidclient/validationdtos.java | 589 ++++++++++++++++++ .../res/layout/fragment_top_technologies.xml | 11 +- 3 files changed, 633 insertions(+), 2 deletions(-) create mode 100644 src/AndroidClient/app/src/main/java/servicestack/net/androidclient/validationdtos.java diff --git a/src/AndroidClient/app/src/main/java/servicestack/net/androidclient/MainActivity.java b/src/AndroidClient/app/src/main/java/servicestack/net/androidclient/MainActivity.java index fda62c37..495c5d59 100644 --- a/src/AndroidClient/app/src/main/java/servicestack/net/androidclient/MainActivity.java +++ b/src/AndroidClient/app/src/main/java/servicestack/net/androidclient/MainActivity.java @@ -30,6 +30,10 @@ import android.view.ViewGroup; import android.widget.TextView; +import net.servicestack.android.AndroidServiceClient; +import net.servicestack.client.AsyncSuccess; +import net.servicestack.client.Log; + public class MainActivity extends FragmentActivity implements ActionBar.TabListener { /** @@ -175,6 +179,37 @@ public void onClick(View view) { } }); + rootView.findViewById(R.id.btn_test_cookie) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { +// final AndroidServiceClient client = new AndroidServiceClient("http://validation.web-app.io", getContext()); + final AndroidServiceClient client = new AndroidServiceClient("http://validation.web-app.io"); + client.postAsync(new validationdtos.Authenticate() + .setProvider("credentials") + .setUserName("admin@email.com") + .setPassword("p@55wOrd") + , new AsyncSuccess() { + @Override + public void success(validationdtos.AuthenticateResponse response) { + try { + client.setTokenCookie(response.getBearerToken()); + } catch (Exception e) { + Log.e(e); + } + client.getAsync(new validationdtos.GetContacts(), new AsyncSuccess() { + @Override + public void success(validationdtos.GetContactsResponse response) { + for (validationdtos.Contact contact : response.results) { + Log.d("CONTACT: " + contact.name); + } + } + }); + } + }); + } + }); + return rootView; } } diff --git a/src/AndroidClient/app/src/main/java/servicestack/net/androidclient/validationdtos.java b/src/AndroidClient/app/src/main/java/servicestack/net/androidclient/validationdtos.java new file mode 100644 index 00000000..359fe66c --- /dev/null +++ b/src/AndroidClient/app/src/main/java/servicestack/net/androidclient/validationdtos.java @@ -0,0 +1,589 @@ +/* Options: +Date: 2020-03-03 06:32:48 +Version: 5.81 +Tip: To override a DTO option, remove "//" prefix before updating +BaseUrl: http://validation.web-app.io + +Package: servicestack.net.androidclient +GlobalNamespace: validationdtos +//AddPropertyAccessors: True +//SettersReturnThis: True +//AddServiceStackTypes: True +//AddResponseStatus: False +//AddDescriptionAsComments: True +//AddImplicitVersion: +//IncludeTypes: +//ExcludeTypes: +//TreatTypesAsStrings: +//DefaultImports: java.math.*,java.util.*,net.servicestack.client.*,com.google.gson.annotations.*,com.google.gson.reflect.* +*/ + +package servicestack.net.androidclient; + +import java.math.*; +import java.util.*; +import net.servicestack.client.*; +import com.google.gson.annotations.*; +import com.google.gson.reflect.*; + +public class validationdtos +{ + + @Route(Path="/contacts", Verbs="GET") + public static class GetContacts implements IReturn + { + + private static Object responseType = GetContactsResponse.class; + public Object getResponseType() { return responseType; } + } + + @Route(Path="/contacts/{Id}", Verbs="GET") + public static class GetContact implements IReturn + { + public Integer id = null; + + public Integer getId() { return id; } + public GetContact setId(Integer value) { this.id = value; return this; } + private static Object responseType = GetContactResponse.class; + public Object getResponseType() { return responseType; } + } + + @Route(Path="/contacts", Verbs="POST") + public static class CreateContact implements IReturn + { + public Title title = null; + public String name = null; + public String color = null; + public ArrayList filmGenres = null; + public Integer age = null; + public Boolean agree = null; + @SerializedName("continue") public String Continue = null; + public String errorView = null; + + public Title getTitle() { return title; } + public CreateContact setTitle(Title value) { this.title = value; return this; } + public String getName() { return name; } + public CreateContact setName(String value) { this.name = value; return this; } + public String getColor() { return color; } + public CreateContact setColor(String value) { this.color = value; return this; } + public ArrayList getFilmGenres() { return filmGenres; } + public CreateContact setFilmGenres(ArrayList value) { this.filmGenres = value; return this; } + public Integer getAge() { return age; } + public CreateContact setAge(Integer value) { this.age = value; return this; } + public Boolean isAgree() { return agree; } + public CreateContact setAgree(Boolean value) { this.agree = value; return this; } + public String getContinue() { return Continue; } + public CreateContact setContinue(String value) { this.Continue = value; return this; } + public String getErrorView() { return errorView; } + public CreateContact setErrorView(String value) { this.errorView = value; return this; } + private static Object responseType = CreateContactResponse.class; + public Object getResponseType() { return responseType; } + } + + @Route(Path="/contacts/{Id}", Verbs="DELETE") + // @Route(Path="/contacts/{Id}/delete", Verbs="POST") + public static class DeleteContact implements IReturnVoid + { + public Integer id = null; + @SerializedName("continue") public String Continue = null; + + public Integer getId() { return id; } + public DeleteContact setId(Integer value) { this.id = value; return this; } + public String getContinue() { return Continue; } + public DeleteContact setContinue(String value) { this.Continue = value; return this; } + } + + @Route(Path="/contacts/{Id}", Verbs="POST PUT") + public static class UpdateContact implements IReturn + { + public Integer id = null; + public Title title = null; + public String name = null; + public String color = null; + public ArrayList filmGenres = null; + public Integer age = null; + @SerializedName("continue") public String Continue = null; + public String errorView = null; + + public Integer getId() { return id; } + public UpdateContact setId(Integer value) { this.id = value; return this; } + public Title getTitle() { return title; } + public UpdateContact setTitle(Title value) { this.title = value; return this; } + public String getName() { return name; } + public UpdateContact setName(String value) { this.name = value; return this; } + public String getColor() { return color; } + public UpdateContact setColor(String value) { this.color = value; return this; } + public ArrayList getFilmGenres() { return filmGenres; } + public UpdateContact setFilmGenres(ArrayList value) { this.filmGenres = value; return this; } + public Integer getAge() { return age; } + public UpdateContact setAge(Integer value) { this.age = value; return this; } + public String getContinue() { return Continue; } + public UpdateContact setContinue(String value) { this.Continue = value; return this; } + public String getErrorView() { return errorView; } + public UpdateContact setErrorView(String value) { this.errorView = value; return this; } + private static Object responseType = UpdateContactResponse.class; + public Object getResponseType() { return responseType; } + } + + @Route("/auth") + // @Route("/auth/{provider}") + @DataContract + public static class Authenticate implements IReturn, IPost + { + @DataMember(Order=1) + public String provider = null; + + @DataMember(Order=2) + public String state = null; + + @DataMember(Order=3) + public String oauth_token = null; + + @DataMember(Order=4) + public String oauth_verifier = null; + + @DataMember(Order=5) + public String userName = null; + + @DataMember(Order=6) + public String password = null; + + @DataMember(Order=7) + public Boolean rememberMe = null; + + @DataMember(Order=9) + public String errorView = null; + + @DataMember(Order=10) + public String nonce = null; + + @DataMember(Order=11) + public String uri = null; + + @DataMember(Order=12) + public String response = null; + + @DataMember(Order=13) + public String qop = null; + + @DataMember(Order=14) + public String nc = null; + + @DataMember(Order=15) + public String cnonce = null; + + @DataMember(Order=16) + public Boolean useTokenCookie = null; + + @DataMember(Order=17) + public String accessToken = null; + + @DataMember(Order=18) + public String accessTokenSecret = null; + + @DataMember(Order=19) + public String scope = null; + + @DataMember(Order=20) + public HashMap meta = null; + + public String getProvider() { return provider; } + public Authenticate setProvider(String value) { this.provider = value; return this; } + public String getState() { return state; } + public Authenticate setState(String value) { this.state = value; return this; } + public String getOauthToken() { return oauth_token; } + public Authenticate setOauthToken(String value) { this.oauth_token = value; return this; } + public String getOauthVerifier() { return oauth_verifier; } + public Authenticate setOauthVerifier(String value) { this.oauth_verifier = value; return this; } + public String getUserName() { return userName; } + public Authenticate setUserName(String value) { this.userName = value; return this; } + public String getPassword() { return password; } + public Authenticate setPassword(String value) { this.password = value; return this; } + public Boolean isRememberMe() { return rememberMe; } + public Authenticate setRememberMe(Boolean value) { this.rememberMe = value; return this; } + public String getErrorView() { return errorView; } + public Authenticate setErrorView(String value) { this.errorView = value; return this; } + public String getNonce() { return nonce; } + public Authenticate setNonce(String value) { this.nonce = value; return this; } + public String getUri() { return uri; } + public Authenticate setUri(String value) { this.uri = value; return this; } + public String getResponse() { return response; } + public Authenticate setResponse(String value) { this.response = value; return this; } + public String getQop() { return qop; } + public Authenticate setQop(String value) { this.qop = value; return this; } + public String getNc() { return nc; } + public Authenticate setNc(String value) { this.nc = value; return this; } + public String getCnonce() { return cnonce; } + public Authenticate setCnonce(String value) { this.cnonce = value; return this; } + public Boolean isUseTokenCookie() { return useTokenCookie; } + public Authenticate setUseTokenCookie(Boolean value) { this.useTokenCookie = value; return this; } + public String getAccessToken() { return accessToken; } + public Authenticate setAccessToken(String value) { this.accessToken = value; return this; } + public String getAccessTokenSecret() { return accessTokenSecret; } + public Authenticate setAccessTokenSecret(String value) { this.accessTokenSecret = value; return this; } + public String getScope() { return scope; } + public Authenticate setScope(String value) { this.scope = value; return this; } + public HashMap getMeta() { return meta; } + public Authenticate setMeta(HashMap value) { this.meta = value; return this; } + private static Object responseType = AuthenticateResponse.class; + public Object getResponseType() { return responseType; } + } + + @Route("/assignroles") + @DataContract + public static class AssignRoles implements IReturn, IPost + { + @DataMember(Order=1) + public String userName = null; + + @DataMember(Order=2) + public ArrayList permissions = null; + + @DataMember(Order=3) + public ArrayList roles = null; + + @DataMember(Order=4) + public HashMap meta = null; + + public String getUserName() { return userName; } + public AssignRoles setUserName(String value) { this.userName = value; return this; } + public ArrayList getPermissions() { return permissions; } + public AssignRoles setPermissions(ArrayList value) { this.permissions = value; return this; } + public ArrayList getRoles() { return roles; } + public AssignRoles setRoles(ArrayList value) { this.roles = value; return this; } + public HashMap getMeta() { return meta; } + public AssignRoles setMeta(HashMap value) { this.meta = value; return this; } + private static Object responseType = AssignRolesResponse.class; + public Object getResponseType() { return responseType; } + } + + @Route("/unassignroles") + @DataContract + public static class UnAssignRoles implements IReturn, IPost + { + @DataMember(Order=1) + public String userName = null; + + @DataMember(Order=2) + public ArrayList permissions = null; + + @DataMember(Order=3) + public ArrayList roles = null; + + @DataMember(Order=4) + public HashMap meta = null; + + public String getUserName() { return userName; } + public UnAssignRoles setUserName(String value) { this.userName = value; return this; } + public ArrayList getPermissions() { return permissions; } + public UnAssignRoles setPermissions(ArrayList value) { this.permissions = value; return this; } + public ArrayList getRoles() { return roles; } + public UnAssignRoles setRoles(ArrayList value) { this.roles = value; return this; } + public HashMap getMeta() { return meta; } + public UnAssignRoles setMeta(HashMap value) { this.meta = value; return this; } + private static Object responseType = UnAssignRolesResponse.class; + public Object getResponseType() { return responseType; } + } + + @Route("/register") + @DataContract + public static class Register implements IReturn, IPost + { + @DataMember(Order=1) + public String userName = null; + + @DataMember(Order=2) + public String firstName = null; + + @DataMember(Order=3) + public String lastName = null; + + @DataMember(Order=4) + public String displayName = null; + + @DataMember(Order=5) + public String email = null; + + @DataMember(Order=6) + public String password = null; + + @DataMember(Order=7) + public String confirmPassword = null; + + @DataMember(Order=8) + public Boolean autoLogin = null; + + @DataMember(Order=10) + public String errorView = null; + + @DataMember(Order=11) + public HashMap meta = null; + + public String getUserName() { return userName; } + public Register setUserName(String value) { this.userName = value; return this; } + public String getFirstName() { return firstName; } + public Register setFirstName(String value) { this.firstName = value; return this; } + public String getLastName() { return lastName; } + public Register setLastName(String value) { this.lastName = value; return this; } + public String getDisplayName() { return displayName; } + public Register setDisplayName(String value) { this.displayName = value; return this; } + public String getEmail() { return email; } + public Register setEmail(String value) { this.email = value; return this; } + public String getPassword() { return password; } + public Register setPassword(String value) { this.password = value; return this; } + public String getConfirmPassword() { return confirmPassword; } + public Register setConfirmPassword(String value) { this.confirmPassword = value; return this; } + public Boolean isAutoLogin() { return autoLogin; } + public Register setAutoLogin(Boolean value) { this.autoLogin = value; return this; } + public String getErrorView() { return errorView; } + public Register setErrorView(String value) { this.errorView = value; return this; } + public HashMap getMeta() { return meta; } + public Register setMeta(HashMap value) { this.meta = value; return this; } + private static Object responseType = RegisterResponse.class; + public Object getResponseType() { return responseType; } + } + + public static class GetContactsResponse + { + public ArrayList results = null; + public ResponseStatus responseStatus = null; + + public ArrayList getResults() { return results; } + public GetContactsResponse setResults(ArrayList value) { this.results = value; return this; } + public ResponseStatus getResponseStatus() { return responseStatus; } + public GetContactsResponse setResponseStatus(ResponseStatus value) { this.responseStatus = value; return this; } + } + + public static class GetContactResponse + { + public ResponseStatus responseStatus = null; + public Contact result = null; + + public ResponseStatus getResponseStatus() { return responseStatus; } + public GetContactResponse setResponseStatus(ResponseStatus value) { this.responseStatus = value; return this; } + public Contact getResult() { return result; } + public GetContactResponse setResult(Contact value) { this.result = value; return this; } + } + + public static class CreateContactResponse + { + public ResponseStatus responseStatus = null; + public Contact result = null; + + public ResponseStatus getResponseStatus() { return responseStatus; } + public CreateContactResponse setResponseStatus(ResponseStatus value) { this.responseStatus = value; return this; } + public Contact getResult() { return result; } + public CreateContactResponse setResult(Contact value) { this.result = value; return this; } + } + + public static class UpdateContactResponse + { + public ResponseStatus responseStatus = null; + + public ResponseStatus getResponseStatus() { return responseStatus; } + public UpdateContactResponse setResponseStatus(ResponseStatus value) { this.responseStatus = value; return this; } + } + + @DataContract + public static class AuthenticateResponse implements IHasSessionId, IHasBearerToken + { + @DataMember(Order=11) + public ResponseStatus responseStatus = null; + + @DataMember(Order=1) + public String userId = null; + + @DataMember(Order=2) + public String sessionId = null; + + @DataMember(Order=3) + public String userName = null; + + @DataMember(Order=4) + public String displayName = null; + + @DataMember(Order=5) + public String referrerUrl = null; + + @DataMember(Order=6) + public String bearerToken = null; + + @DataMember(Order=7) + public String refreshToken = null; + + @DataMember(Order=8) + public String profileUrl = null; + + @DataMember(Order=9) + public ArrayList roles = null; + + @DataMember(Order=10) + public ArrayList permissions = null; + + @DataMember(Order=12) + public HashMap meta = null; + + public ResponseStatus getResponseStatus() { return responseStatus; } + public AuthenticateResponse setResponseStatus(ResponseStatus value) { this.responseStatus = value; return this; } + public String getUserId() { return userId; } + public AuthenticateResponse setUserId(String value) { this.userId = value; return this; } + public String getSessionId() { return sessionId; } + public AuthenticateResponse setSessionId(String value) { this.sessionId = value; return this; } + public String getUserName() { return userName; } + public AuthenticateResponse setUserName(String value) { this.userName = value; return this; } + public String getDisplayName() { return displayName; } + public AuthenticateResponse setDisplayName(String value) { this.displayName = value; return this; } + public String getReferrerUrl() { return referrerUrl; } + public AuthenticateResponse setReferrerUrl(String value) { this.referrerUrl = value; return this; } + public String getBearerToken() { return bearerToken; } + public AuthenticateResponse setBearerToken(String value) { this.bearerToken = value; return this; } + public String getRefreshToken() { return refreshToken; } + public AuthenticateResponse setRefreshToken(String value) { this.refreshToken = value; return this; } + public String getProfileUrl() { return profileUrl; } + public AuthenticateResponse setProfileUrl(String value) { this.profileUrl = value; return this; } + public ArrayList getRoles() { return roles; } + public AuthenticateResponse setRoles(ArrayList value) { this.roles = value; return this; } + public ArrayList getPermissions() { return permissions; } + public AuthenticateResponse setPermissions(ArrayList value) { this.permissions = value; return this; } + public HashMap getMeta() { return meta; } + public AuthenticateResponse setMeta(HashMap value) { this.meta = value; return this; } + } + + @DataContract + public static class AssignRolesResponse + { + @DataMember(Order=1) + public ArrayList allRoles = null; + + @DataMember(Order=2) + public ArrayList allPermissions = null; + + @DataMember(Order=3) + public HashMap meta = null; + + @DataMember(Order=4) + public ResponseStatus responseStatus = null; + + public ArrayList getAllRoles() { return allRoles; } + public AssignRolesResponse setAllRoles(ArrayList value) { this.allRoles = value; return this; } + public ArrayList getAllPermissions() { return allPermissions; } + public AssignRolesResponse setAllPermissions(ArrayList value) { this.allPermissions = value; return this; } + public HashMap getMeta() { return meta; } + public AssignRolesResponse setMeta(HashMap value) { this.meta = value; return this; } + public ResponseStatus getResponseStatus() { return responseStatus; } + public AssignRolesResponse setResponseStatus(ResponseStatus value) { this.responseStatus = value; return this; } + } + + @DataContract + public static class UnAssignRolesResponse + { + @DataMember(Order=1) + public ArrayList allRoles = null; + + @DataMember(Order=2) + public ArrayList allPermissions = null; + + @DataMember(Order=3) + public HashMap meta = null; + + @DataMember(Order=4) + public ResponseStatus responseStatus = null; + + public ArrayList getAllRoles() { return allRoles; } + public UnAssignRolesResponse setAllRoles(ArrayList value) { this.allRoles = value; return this; } + public ArrayList getAllPermissions() { return allPermissions; } + public UnAssignRolesResponse setAllPermissions(ArrayList value) { this.allPermissions = value; return this; } + public HashMap getMeta() { return meta; } + public UnAssignRolesResponse setMeta(HashMap value) { this.meta = value; return this; } + public ResponseStatus getResponseStatus() { return responseStatus; } + public UnAssignRolesResponse setResponseStatus(ResponseStatus value) { this.responseStatus = value; return this; } + } + + @DataContract + public static class RegisterResponse + { + @DataMember(Order=7) + public ResponseStatus responseStatus = null; + + @DataMember(Order=1) + public String userId = null; + + @DataMember(Order=2) + public String sessionId = null; + + @DataMember(Order=3) + public String userName = null; + + @DataMember(Order=4) + public String referrerUrl = null; + + @DataMember(Order=5) + public String bearerToken = null; + + @DataMember(Order=6) + public String refreshToken = null; + + @DataMember(Order=8) + public HashMap meta = null; + + public ResponseStatus getResponseStatus() { return responseStatus; } + public RegisterResponse setResponseStatus(ResponseStatus value) { this.responseStatus = value; return this; } + public String getUserId() { return userId; } + public RegisterResponse setUserId(String value) { this.userId = value; return this; } + public String getSessionId() { return sessionId; } + public RegisterResponse setSessionId(String value) { this.sessionId = value; return this; } + public String getUserName() { return userName; } + public RegisterResponse setUserName(String value) { this.userName = value; return this; } + public String getReferrerUrl() { return referrerUrl; } + public RegisterResponse setReferrerUrl(String value) { this.referrerUrl = value; return this; } + public String getBearerToken() { return bearerToken; } + public RegisterResponse setBearerToken(String value) { this.bearerToken = value; return this; } + public String getRefreshToken() { return refreshToken; } + public RegisterResponse setRefreshToken(String value) { this.refreshToken = value; return this; } + public HashMap getMeta() { return meta; } + public RegisterResponse setMeta(HashMap value) { this.meta = value; return this; } + } + + public static class Contact + { + public Integer id = null; + public Integer userAuthId = null; + public Title title = null; + public String name = null; + public String color = null; + public ArrayList filmGenres = null; + public Integer age = null; + + public Integer getId() { return id; } + public Contact setId(Integer value) { this.id = value; return this; } + public Integer getUserAuthId() { return userAuthId; } + public Contact setUserAuthId(Integer value) { this.userAuthId = value; return this; } + public Title getTitle() { return title; } + public Contact setTitle(Title value) { this.title = value; return this; } + public String getName() { return name; } + public Contact setName(String value) { this.name = value; return this; } + public String getColor() { return color; } + public Contact setColor(String value) { this.color = value; return this; } + public ArrayList getFilmGenres() { return filmGenres; } + public Contact setFilmGenres(ArrayList value) { this.filmGenres = value; return this; } + public Integer getAge() { return age; } + public Contact setAge(Integer value) { this.age = value; return this; } + } + + public static enum Title + { + Unspecified, + Mr, + Mrs, + Miss; + } + + public static enum FilmGenres + { + Action, + Adventure, + Comedy, + Drama; + } + +} diff --git a/src/AndroidClient/app/src/main/res/layout/fragment_top_technologies.xml b/src/AndroidClient/app/src/main/res/layout/fragment_top_technologies.xml index 2423c89f..5afe2328 100644 --- a/src/AndroidClient/app/src/main/res/layout/fragment_top_technologies.xml +++ b/src/AndroidClient/app/src/main/res/layout/fragment_top_technologies.xml @@ -28,11 +28,18 @@ android:layout_height="wrap_content" android:text="@string/demo_collection"/> -