Coder Social home page Coder Social logo

finos / symphony-bdk-java Goto Github PK

View Code? Open in Web Editor NEW
22.0 19.0 67.0 4.68 MB

The Symphony BDK (Bot Developer Kit) for Java helps you to create production-grade Chat Bots and Extension Applications on top of the Symphony REST APIs.

Home Page: https://symphony-bdk-java.finos.org

License: Apache License 2.0

Java 97.70% HTML 0.19% FreeMarker 0.07% Handlebars 0.02% CSS 0.01% JavaScript 0.34% Dockerfile 0.01% Mustache 1.67%
symphony bdk bot bot-framework java symphony-bdk finos

symphony-bdk-java's Introduction

Build FINOS - Incubating License Maven Central javadoc

Symphony BDK for Java

Note

BDK version 3.0: Major change !

The newly introduced BDK version 3.0 relies on Java 17 and SpringBoot 3. This is a major change that allows Symphony to continue to propose the latest security fixes following the end of support of Spring Boot 2 and also to keep up with the latest evolutions of Java.

For the next 6 months Symphony will provide critical security fixes for BDK 2.0 where possible (since Spring gives no guarantees for their packages).

Please consider migrating your Bots in the coming months to benefit from the latest features and support.

Important

As detailed above, the BDK version 2.0 will stop being supported by Symphony on August 15.

The official Symphony BDK for Java helps you to create production-grade Chat Bots and Extension Applications on top of the Symphony REST APIs.

Installation and Getting Started

The reference documentation includes detailed installation instructions as well as a comprehensive getting started guide.

Here is a quick teaser of a complete Symphony BDK application in Java:

public class BotApplication {
    
    public static void main(String[] args) {
      
        final SymphonyBdk bdk = new SymphonyBdk(BdkConfigLoader.loadFromSymphonyDir("config.yaml"));
      
        bdk.activities().register(slash("/hello", context -> {
            bdk.messages().send(context.getStreamId(), "<messageML>Hello, World!</messageML>");
        }));
        
        bdk.datafeed().start();
    }
}

Build from Source

The Symphony BDK uses a Gradle build. The instructions below use the Gradle Wrapper from the root of the source tree. The wrapper script serves as a cross-platform, self-contained bootstrap mechanism for the build system.

Before you start

To build you will need Git and JDK 8 or later. Be sure that your JAVA_HOME environment variable points to the jdk1.8+ folder extracted from the JDK download.

Build from the Command Line

To compile, test and build all BDK2.0 jars, use:

./gradlew

To compile, test and build legacy jars:

git checkout legacy
./gradlew

Legacy modules (SDK and BDK 1.0) have been moved to the legacy branch

Install in local Maven repository

To install all Symphony BDK jars in your local Maven repository, use:

./gradlew publishToMavenLocal

Contributing

In order to get in touch with the project team, please open a GitHub Issue. Alternatively, you can email/subscribe to [email protected].

  1. Fork it (https://github.com/finos/symphony-bdk-java/fork)
  2. Create your feature branch (git checkout -b feature/fooBar)
  3. Read our contribution guidelines and Community Code of Conduct
  4. Commit your changes (git commit -am 'Add some fooBar')
  5. Push to the branch (git push origin feature/fooBar)
  6. Create a new Pull Request

NOTE: Commits and pull requests to FINOS repositories will only be accepted from those contributors with an active, executed Individual Contributor License Agreement (ICLA) with FINOS OR who are covered under an existing and active Corporate Contribution License Agreement (CCLA) executed with FINOS. Commits from individuals not covered under an ICLA or CCLA will be flagged and blocked by the FINOS Clabot tool. Please note that some CCLAs require individuals/employees to be explicitly named on the CCLA.

Need an ICLA? Unsure if you are covered under an existing CCLA? Email [email protected]

Thanks to all the people who have contributed

contributors

License

Copyright 2021 Symphony LLC

Distributed under the Apache License, Version 2.0.

SPDX-License-Identifier: Apache-2.0

symphony-bdk-java's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

symphony-bdk-java's Issues

Wrong pagination logic for listAllUserFollowing and listAllUserFollowers

Bug Report

Today we are using an offset based pagination logic for endpoints that have a cursor based pagination:

However, the documentation of these endpoints list user followers and list user followed explains the logic for pagination:

  • the after query param means we fetch the item of rank after + 1
  • if pagination.cursors.after is not present in the response payload, it means last item is in the current payload

Logic should go as follows:

  • first call with no after and no before query param
  • next calls are done with after query param retrieved from the previous response payload
  • when after is not present in the response payload, we are done

Extended API: Open Chat

Extended API: Open Chat

Hello everyone! I was wondering if I can open a specific Symphony chat using the Extended Javascript API. Is it possible?

FormReplyActivity throws NPE for unchecked checkboxes

Bug Report

Steps to Reproduce:

  1. Sending an elements form with a checkbox, leaving it unchecked

    <checkbox name="checkbox" value="value">Unchecked</checkbox>
  2. Use FormReplyActivity to getFormValue

    @Override
    public void onActivity(FormReplyContext context) {
      String checkbox = context.getFormValue("checkbox"); // NPE thrown
      this.messageService.send(context.getSourceEvent().getStream(), "hi");
    }

Expected Result:

return null or false instead

Actual Result:

java.lang.NullPointerException: Cannot invoke "com.fasterxml.jackson.databind.JsonNode.asText()" because the return value of "com.fasterxml.jackson.databind.JsonNode.get(String)" is null
	at com.symphony.bdk.core.activity.form.FormReplyContext.getFormValue(FormReplyContext.java:38)
	at com.symphony.GifFormActivity.onActivity(GifFormActivity.java:31)
	at com.symphony.GifFormActivity.onActivity(GifFormActivity.java:12)
	at com.symphony.bdk.core.activity.AbstractActivity.processEvent(AbstractActivity.java:91)
	at com.symphony.bdk.core.service.datafeed.util.RealTimeEventsBinder$2.onSymphonyElementsAction(RealTimeEventsBinder.java:50)
	at com.symphony.bdk.core.service.datafeed.impl.RealTimeEventType.lambda$static$2(RealTimeEventType.java:24)
	at com.symphony.bdk.core.service.datafeed.impl.RealTimeEventType.dispatch(RealTimeEventType.java:73)
	at com.symphony.bdk.core.service.datafeed.impl.AbstractDatafeedLoop.handleV4EventList(AbstractDatafeedLoop.java:85)
	at com.symphony.bdk.core.service.datafeed.impl.DatafeedLoopV1.readAndHandleEvents(DatafeedLoopV1.java:107)
	at com.symphony.bdk.core.retry.RetryWithRecovery.executeOnce(RetryWithRecovery.java:86)
	at io.github.resilience4j.retry.Retry.lambda$decorateCheckedSupplier$3f69f149$1(Retry.java:137)
	at io.github.resilience4j.retry.Retry.executeCheckedSupplier(Retry.java:419)
	at com.symphony.bdk.core.retry.resilience4j.Resilience4jRetryWithRecovery.execute(Resilience4jRetryWithRecovery.java:65)
	at com.symphony.bdk.core.service.datafeed.impl.DatafeedLoopV1.readDatafeed(DatafeedLoopV1.java:119)
	at com.symphony.bdk.core.service.datafeed.impl.DatafeedLoopV1.start(DatafeedLoopV1.java:84)
	at com.symphony.BotApplication.main(BotApplication.java:39)

CVE-2021-21290 (Medium) detected in netty-handler-4.1.55.Final.jar, netty-codec-http-4.1.55.Final.jar - autoclosed

CVE-2021-21290 - Medium Severity Vulnerability

Vulnerable Libraries - netty-handler-4.1.55.Final.jar, netty-codec-http-4.1.55.Final.jar

netty-handler-4.1.55.Final.jar

Library home page: https://netty.io/

Path to dependency file: symphony-bdk-java/symphony-bdk-core/build.gradle

Path to vulnerable library: /home/wss-scanner/.gradle/caches/modules-2/files-2.1/io.netty/netty-handler/4.1.55.Final/38c512292e8357288798d29165b1d3188900d353/netty-handler-4.1.55.Final.jar

Dependency Hierarchy:

  • mockserver-netty-5.11.1.jar (Root Library)
    • mockserver-client-java-5.11.1.jar
      • mockserver-core-5.11.1.jar
        • โŒ netty-handler-4.1.55.Final.jar (Vulnerable Library)
netty-codec-http-4.1.55.Final.jar

Library home page: https://netty.io/

Path to dependency file: symphony-bdk-java/symphony-bdk-core/build.gradle

Path to vulnerable library: /home/wss-scanner/.gradle/caches/modules-2/files-2.1/io.netty/netty-codec-http/4.1.55.Final/b8bf56395a316b1491f0497f53247da484f4523a/netty-codec-http-4.1.55.Final.jar

Dependency Hierarchy:

  • mockserver-netty-5.11.1.jar (Root Library)
    • mockserver-client-java-5.11.1.jar
      • mockserver-core-5.11.1.jar
        • โŒ netty-codec-http-4.1.55.Final.jar (Vulnerable Library)

Found in HEAD commit: 369e011299ab27a6e2381867a8a9f24de7ae341b

Found in base branch: master

Vulnerability Details

Netty is an open-source, asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. In Netty before version 4.1.59.Final there is a vulnerability on Unix-like systems involving an insecure temp file. When netty's multipart decoders are used local information disclosure can occur via the local system temporary directory if temporary storing uploads on the disk is enabled. On unix-like systems, the temporary directory is shared between all user. As such, writing to this directory using APIs that do not explicitly set the file/directory permissions can lead to information disclosure. Of note, this does not impact modern MacOS Operating Systems. The method "File.createTempFile" on unix-like systems creates a random file, but, by default will create this file with the permissions "-rw-r--r--". Thus, if sensitive information is written to this file, other local users can read this information. This is the case in netty's "AbstractDiskHttpData" is vulnerable. This has been fixed in version 4.1.59.Final. As a workaround, one may specify your own "java.io.tmpdir" when you start the JVM or use "DefaultHttpDataFactory.setBaseDir(...)" to set the directory to something that is only readable by the current user.

Publish Date: 2021-02-08

URL: CVE-2021-21290

CVSS 3 Score Details (6.2)

Base Score Metrics:

  • Exploitability Metrics:
    • Attack Vector: Local
    • Attack Complexity: Low
    • Privileges Required: None
    • User Interaction: None
    • Scope: Unchanged
  • Impact Metrics:
    • Confidentiality Impact: High
    • Integrity Impact: None
    • Availability Impact: None

For more information on CVSS3 Scores, click here.

Suggested Fix

Type: Upgrade version

Origin: GHSA-5mcr-gq6c-3hq2

Release Date: 2021-02-08

Fix Resolution: io.netty:netty-codec-http:4.1.59.Final

DatafeedLoop async dispatch

Feature Request

Description of Problem:

In the current implementation of the AbstractDatafeedLoop, received events are dispatch synchronously and sequentially within the loop thread.

Here's bellow the part of code used to dispatch incoming events to registered listeners:

  protected void handleV4EventList(List<V4Event> events) {
    for (V4Event event : events) {
      if (event == null || event.getType() == null) {
        continue;
      }

      try {
        RealTimeEventType eventType = RealTimeEventType.valueOf(event.getType());
        for (RealTimeEventListener listener : listeners) {
          if (listener.isAcceptingEvent(event, bdkConfig.getBot().getUsername())) {
            eventType.dispatch(listener, event);
          }
        }
      } catch (IllegalArgumentException e) {
        log.warn("Receive events with unknown type: {}", event.getType());
      }
    }
  }

This might cause serious problems when a listener (e.g. RealTimeEventsListener) takes long time to process an incoming event. For instance a call to an external service or even a database query.

Potential Solutions:

A potential solution is to dispatch received events using a configurable fixed thread pool:

  /** Executor service used to dispatch events to {@link RealTimeEventListener} list */
  private final ExecutorService executorService = Executors.newFixedThreadPool(10);

  protected void handleV4EventList(List<V4Event> events) {
    for (V4Event event : events) {
      if (event == null || event.getType() == null) {
        continue;
      }

      try {
        RealTimeEventType eventType = RealTimeEventType.valueOf(event.getType());
        for (RealTimeEventListener listener : listeners) {
          if (listener.isAcceptingEvent(event, bdkConfig.getBot().getUsername())) {
            this.executorService.execute(() -> {
              try {
                eventType.dispatch(listener, event);
              } catch (Exception e) {
                log.debug("An error has occurred while dispatching event={} to listener={}", event, listener, e);
              }
            });
          }
        }
      } catch (IllegalArgumentException e) {
        log.warn("Receive events with unknown type: {}", event.getType());
      }
    }
  }

ConcurrentModificationException in Datafeed loop

Bug Report

A ConcurrentModificationException can happen in the Datafeed (DF) loop upon startup.

The access to the listeners collection in the DF loop is not protected and accessed by multiple threads. Synchronizing the list should help to that matter.

Steps to Reproduce:

This is not always happening but restarting a bot using the DF loop and receiving events while starting should raise the issue.

Expected Result:

No exception.

Actual Result:

2021-03-15T17:28:38,530Z DEBUG [SymphonyBdk_DatafeedThread-111] c.s.b.c.r.RetryWithRecovery : Exception recovered
java.util.ConcurrentModificationException: null
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911) ~[?:1.8.0_272]
	at java.util.ArrayList$Itr.next(ArrayList.java:861) ~[?:1.8.0_272]
	at com.symphony.bdk.core.service.datafeed.impl.AbstractDatafeedLoop.handleV4EventList(AbstractDatafeedLoop.java:82) ~[symphony-bdk-core-2.1.1.jar!/:2.1.1]
	at com.symphony.bdk.core.service.datafeed.impl.DatafeedLoopV1.readAndHandleEvents(DatafeedLoopV1.java:109) ~[symphony-bdk-core-2.1.1.jar!/:2.1.1]
	at com.symphony.bdk.core.retry.RetryWithRecovery.executeOnce(RetryWithRecovery.java:95) ~[symphony-bdk-core-2.1.1.jar!/:2.1.1]
	at io.github.resilience4j.retry.Retry.lambda$decorateCheckedSupplier$3f69f149$1(Retry.java:137) ~[resilience4j-retry-1.5.0.jar!/:1.5.0]
	at io.github.resilience4j.retry.Retry.executeCheckedSupplier(Retry.java:419) ~[resilience4j-retry-1.5.0.jar!/:1.5.0]
	at com.symphony.bdk.core.retry.resilience4j.Resilience4jRetryWithRecovery.execute(Resilience4jRetryWithRecovery.java:65) ~[symphony-bdk-core-2.1.1.jar!/:2.1.1]
	at com.symphony.bdk.core.service.datafeed.impl.DatafeedLoopV1.readDatafeed(DatafeedLoopV1.java:121) ~[symphony-bdk-core-2.1.1.jar!/:2.1.1]
	at com.symphony.bdk.core.service.datafeed.impl.DatafeedLoopV1.start(DatafeedLoopV1.java:86) ~[symphony-bdk-core-2.1.1.jar!/:2.1.1]
	at com.symphony.bdk.spring.service.DatafeedAsyncLauncherService.uncheckedStart(DatafeedAsyncLauncherService.java:88) ~[symphony-bdk-core-spring-boot-starter-2.1.1.jar!/:2.1.1]
	at com.symphony.bdk.http.api.tracing.MDCUtils$MdcRunnable.run(MDCUtils.java:59) [symphony-bdk-http-api-2.1.1.jar!/:2.1.1]
	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_272]

Document HttpClient usage

The BDK proposes a generic HttpClient that allows developers to perform calls to external systems.

The advantage of this HttpClient is it relies on the same implementations that are used to perform calls to the Symphony REST APIs.

Also, developers are free to choose between different implementations by simply selecting the right dependency:

<dependency>
   <groupId>org.finos.symphony.bdk</groupId>
   <artifactId>symphony-bdk-http-jersey2</artifactId>
   <scope>runtime</scope>
</dependency>
<!-- OR -->
<dependency>
   <groupId>org.finos.symphony.bdk</groupId>
   <artifactId>symphony-bdk-http-webclient</artifactId>
   <scope>runtime</scope>
</dependency>

What do we want?

  • create new http-client.md in ./docs/ folder
  • reference this file in index.md
  • document configuration and usage of the HttpClient interface and its different implementations

Error logging in SymBotRSAAuth would benefit from more info

Hello,

When using the api on a remote server, I get the following error (no stacktrace):

2018-09-20 15:30:50.519 ERROR [messaging-connector,a8a59305c83091d4,a8a59305c83091d4,false] 5244 --- [nio-8080-exec-1] authentication.SymBotAuth                : Unexpected error, retry authentication in 30 seconds

It would be nice to log the stackTrace at least for the first error occurence to simplify diagnostics.

Thanks

ConnectionListener returns wrong user for ConnectionRequested/Accepted

In DatafeedEventsService.java I see the following code:

case "CONNECTIONREQUESTED":
    for (ConnectionListener listener : connectionListeners) {
        listener.onConnectionRequested(event.getInitiator().getUser());
    }
    break;

event.getInitiator() returns the user who received the event, i.e. the bot account, not the user who has requested the connection. This can easily be seen from the code where it compares the initiator of the event message to the current bot user.

What I would expect to see instead is:

case "CONNECTIONREQUESTED":
    for (ConnectionListener listener : connectionListeners) {
        User toUser = event.getPayload().getConnectedRequested().getToUser();
        listener.onConnectionRequested(toUser);
    }
    break;

Pass an custom ObjectMapper to the ApiClient

Feature Request

As BDK user, I'd like to be able to pass a custom ObjectMapper to the ApiClient.

Description of Problem:

This feature allows us to have a specific marshalling configuration for some special java objects, e.g. datetime, by default it is mapped into a long type, while we need a string in a specific format. Jira ticket https://perzoinc.atlassian.net/browse/PLAT-10517

...please resist the temptation to describe your request in terms of a solution. Job Story form ("When [triggering condition], I want to [motivation/goal], so I can [outcome].") can help ensure you're expressing a problem statement.

Potential Solutions:

...clearly and concisely describe what you want to happen. Add any considered drawbacks.

... if you've considered alternatives, clearly and concisely describe those too.

Cookie set without SameSite=Strict

Bug Report

The request to
/bdk/v1/app/auth
appears to be vulnerable to cross-site request forgery (CSRF) attacks against authenticated users.

The request can be issued cross-domain.
The BDK relies solely on HTTP cookies to identify the user that issued the request.
The request performs some privileged action within the application, which returns a token.
The attacker can determine all the parameters required to construct a request that performs the action. If the request contains any values that the attacker cannot determine or predict, then it is not vulnerable.

Steps to Reproduce:

  1. .Send an HTTP request to /bdk/v1/app/auth by modifying the Referer (see below)
    image
  2. The request passes and the token is obtained:
    image

Expected Result:

Should return a 401 (Not authenticated), because the Cookie should not be sent (auth cookie not sent = not authenticated)

Actual Result:

The request passes through, because of the Cookie which is sent, due to the fact that it does not contain the Strict value for Samesite attribute (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#strict).

Environment:

None

Additional Context:

None

Recommendation:

Set the Strict value to the Samesite attribute. This will prevent sending the cookie when the request is done from another domain.

InboundMessage issue

Hi,

I've noticed that if user provides message starting/ending with spaces and we want to remove them in our listener by doing something like
inboundMessage.setMessage( inboundMessage.getMessageText.trim())

Then I assume that inboundMessage.getMessage() should have the same value as inboundMessageText(). It's not because of InboundMessage.messageText field is calculated only once.

Could you please check?

Remove tomcat dependency from app-starter

Feature Request

Description of Problem:

com.symphony.bdk.app.spring.auth.CircleOfTrustController has a dependency on org.apache.tomcat.util.http.SameSiteCookies, which is coming from embed core tomcat.

Remove this dependency so that client can use another embedded server such as undertow.

Update User-Agent default value to comply with RFC 7231 section 5.5.3

Default user-agent is currently "Symphony BDK/" + getBdkVersion() + "/java/" + System.getProperty("java.version") as defined here: https://github.com/finos/symphony-bdk-java/blob/main/symphony-bdk-http/symphony-bdk-http-api/src/main/java/com/symphony/bdk/http/api/util/ApiUtils.java#L14

According to https://tools.ietf.org/html/rfc7231#section-5.5.3 we should have no spaces within the same
product item in the User-Agent field.

Expected Result:

I would propose to have the following instead:
"Symphony-BDK-Java/" + getBdkVersion() + " Java/" + System.getProperty("java.version")

CVE-2020-8908 (Low) detected in guava-28.2-android.jar - autoclosed

CVE-2020-8908 - Low Severity Vulnerability

Vulnerable Library - guava-28.2-android.jar

Guava is a suite of core and expanded libraries that include utility classes, google's collections, io classes, and much much more.

Library home page: https://github.com/google/guava

Path to dependency file: symphony-bdk-java/symphony-bdk-core/build.gradle

Path to vulnerable library: /tmp/ws-ua_20210421083448_VPEHNJ/downloadResource_ATFSSK/20210421083927/guava-28.2-android.jar

Dependency Hierarchy:

  • mockserver-netty-5.11.1.jar (Root Library)
    • โŒ guava-28.2-android.jar (Vulnerable Library)

Found in HEAD commit: 369e011299ab27a6e2381867a8a9f24de7ae341b

Found in base branch: main

Vulnerability Details

A temp directory creation vulnerability exists in all versions of Guava, allowing an attacker with access to the machine to potentially access data in a temporary directory created by the Guava API com.google.common.io.Files.createTempDir(). By default, on unix-like systems, the created directory is world-readable (readable by an attacker with access to the system). The method in question has been marked @deprecated in versions 30.0 and later and should not be used. For Android developers, we recommend choosing a temporary directory API provided by Android, such as context.getCacheDir(). For other Java developers, we recommend migrating to the Java 7 API java.nio.file.Files.createTempDirectory() which explicitly configures permissions of 700, or configuring the Java runtime's java.io.tmpdir system property to point to a location whose permissions are appropriately configured.

Publish Date: 2020-12-10

URL: CVE-2020-8908

CVSS 3 Score Details (3.3)

Base Score Metrics:

  • Exploitability Metrics:
    • Attack Vector: Local
    • Attack Complexity: Low
    • Privileges Required: Low
    • User Interaction: None
    • Scope: Unchanged
  • Impact Metrics:
    • Confidentiality Impact: Low
    • Integrity Impact: None
    • Availability Impact: None

For more information on CVSS3 Scores, click here.

Suggested Fix

Type: Upgrade version

Origin: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-8908

Release Date: 2020-12-10

Fix Resolution: v30.0

SymBotAuth.kmAuthClient doesn't use proxy settings

Hello,

I have an error when using config.json config with a proxy :

UnknownHostException: xxx-api.symphony.com.

kmAuthClient doesn't use proxy settings (see https://github.com/SymphonyPlatformSolutions/symphony-api-client-java/blob/9a8c4f141c6b9e30609800d462d6218b97b41f0e/src/main/java/authentication/SymBotAuth.java#L37)

Sample config.json:

{
  "sessionAuthHost": "xxx-api.symphony.com",
  "sessionAuthPort": 443,
  "keyAuthHost": "xxx-api.symphony.com",
  "keyAuthPort": 443,
  "podHost": "xxx-api.symphony.com",
  "podPort": 443,
  "agentHost": "xxx-api.symphony.com",
  "agentPort": 443,
  "botCertPath": "C:\\keys\\",
  "botCertName": "bot",
  "botCertPassword": "changeit",
  "botEmailAddress": "BOT-EMAIL-ADDRESS",
  "appCertPath": "",
  "appCertName": "",
  "appCertPassword": "",
  "proxyURL": "http://proxy:8080",
  "proxyUsername": "user",
  "proxyPassword": "pwd"
}

Full stacktrace:

10:38:36.759 [main] INFO authentication.SymBotAuth - KM auth
Disconnected from the target VM, address: '127.0.0.1:50289', transport: 'socket'
Exception in thread "main" javax.ws.rs.ProcessingException: java.net.UnknownHostException: xxx-api.symphony.com
	at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:287)
	at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:252)
	at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:684)
	at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:681)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
	at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:681)
	at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:437)
	at org.glassfish.jersey.client.JerseyInvocation$Builder.post(JerseyInvocation.java:343)
	at authentication.SymBotAuth.kmAuthenticate(SymBotAuth.java:141)
	at authentication.SymBotAuth.authenticate(SymBotAuth.java:83)
	at com.xxx.chatbot.symphony.BotExample.<init>(BotExample.java:42)
	at com.xxx.chatbot.symphony.BotExample.main(BotExample.java:16)
Caused by: java.net.UnknownHostException: xxx-api.symphony.com
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:184)
	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
	at java.net.Socket.connect(Socket.java:589)
	at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:668)
	at sun.net.NetworkClient.doConnect(NetworkClient.java:175)
	at sun.net.www.http.HttpClient.openServer(HttpClient.java:463)
	at sun.net.www.http.HttpClient.openServer(HttpClient.java:558)
	at sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:264)
	at sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:367)
	at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:191)
	at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1138)
	at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1032)
	at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:177)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1546)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
	at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
	at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:338)
	at org.glassfish.jersey.client.internal.HttpUrlConnector._apply(HttpUrlConnector.java:399)
	at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:285)
	... 14 more

FreeMarkerEngine configurability

Feature Request

As BDK FreeMarker template user, i'd like to be able to configure a multiple template loader, the loader path is configurable(filepath or classpath), so that the templates files are going to be loaded from these paths, and will be override according to the loader's order. I'd like also be able to configure the freemarker configurations such like cache and template update delay.

Description of Problem:

FreeMarkerEngine from BDK2.0 has a private createConfiguration() method, so that cannot be override to have a custom configuration, in addition, each call newTemplateFromFile, or newTemplateFromClasspath will create a new configuration on the fly, this won't profit the template caching from Freemarker, hence we will have a bit performance impact.

Potential Solutions:

.To see if this is something we'd like to do in BDK, otherwise we already have an custom implementation of FreeMarkerEngine to satisfy our requirement.

... if you've considered alternatives, clearly and concisely describe those too.

Symphony bot client thread safety

Hello everybody,

I was wondering if Symphony bot client class (SymBotClient) is thread safe. The question is:
can I send a message from different threads using the same istance of SymBotClient?

Thanks

NPE in DatafeedEventsService when error is raised by datafeedClient.readDatafeed

Hello,

We can have an NPE error in DatafeedEventsService whenever DatafeedEventsService.lambda$readDatafeed$3(DatafeedEventsService.java:97) throws an exception.

Sample stacktrace:

java.util.concurrent.ExecutionException: java.lang.NullPointerException
	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at services.DatafeedEventsService.lambda$readDatafeed$3(DatafeedEventsService.java:97)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException
	at services.DatafeedEventsService.lambda$null$2(DatafeedEventsService.java:90)
	at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:602)
	at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:577)
	at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1595)
	... 3 more

In my case, the original error that was at the origin of the NPE was:

2018-09-25 08:52:19.257 ERROR [messaging-connector,,,] 300272 --- [pool-4-thread-4] services.DatafeedEventsService           : java.lang.RuntimeException: javax.ws.rs.ProcessingException: java.net.UnknownHostException: myproxy
java.util.concurrent.ExecutionException: javax.ws.rs.ProcessingException: java.net.UnknownHostException: myproxy
	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at services.DatafeedEventsService.lambda$readDatafeed$3(DatafeedEventsService.java:97)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:748)
Caused by: javax.ws.rs.ProcessingException: java.net.UnknownHostException: proxyusers
	at org.glassfish.jersey.apache.connector.ApacheConnector.apply(ApacheConnector.java:496)
	at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:252)
	at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:684)
	at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:681)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
	at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:681)
	at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:437)
	at org.glassfish.jersey.client.JerseyInvocation$Builder.post(JerseyInvocation.java:343)
	at clients.symphony.api.DatafeedClient.createDatafeed(DatafeedClient.java:45)
	at services.DatafeedEventsService.handleError(DatafeedEventsService.java:130)
	at services.DatafeedEventsService.lambda$null$1(DatafeedEventsService.java:86)
	at java.util.concurrent.CompletableFuture.uniExceptionally(CompletableFuture.java:870)
	at java.util.concurrent.CompletableFuture$UniExceptionally.tryFire(CompletableFuture.java:852)
	at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1595)
	... 3 more
Caused by: java.net.UnknownHostException: proxyusers
	at java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method)
	at java.net.InetAddress$2.lookupAllHostAddr(InetAddress.java:928)
	at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1323)
	at java.net.InetAddress.getAllByName0(InetAddress.java:1276)
	at java.net.InetAddress.getAllByName(InetAddress.java:1192)
	at java.net.InetAddress.getAllByName(InetAddress.java:1126)
	at org.apache.http.impl.conn.SystemDefaultDnsResolver.resolve(SystemDefaultDnsResolver.java:45)
	at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:112)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:373)
	at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:389)
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:72)
	at org.glassfish.jersey.apache.connector.ApacheConnector.apply(ApacheConnector.java:450)
	... 20 more

ListEnterpriseStreams method of AdminClient doesn't set the values for isActive, isPublic, isExternal flags in AdminStreamInfo

When we call listEnterpriseStreams method on AdminClient, the list of AdminStreamInfo objects returning, but the values not setting for important flags (isActive, isPublic, isExternal) and always it's values are 'false'. But when we hit the actual end-point on Symphony we are getting these values as a result.

This is forcing us to call one more API call to get RoomInfo for the above flags.

Please fix this ASAP.

Post object rather than long

src/main/java/clients/symphony/api/ConnectionsClient.java

acceptConnectionRequest() and rejectConnectionRequest() need to post

Entity.entity(userIdObject, MediaType.APPLICATION_JSON)

rather than

Entity.entity(userId, MediaType.APPLICATION_JSON)

Make agent and pod proxies configurable individually via JSON config

The config.json allows for a proxy to be defined for the Pod and the Agent, but does not allow a single proxy to be defined for only the pod or only the proxy. However there is a second constructor that allows two separate Jersey ClientConfig objects to be passed in, configuring the clients. The issue is that the clients do not use the trust store like the other client setup. See the code snippets below:

The SymBotClient has two constructors, one creates a and the other creates a single conf

private SymBotClient(final SymConfig configuration,
                         final ISymAuth symBotAuthImp,
                         final ClientConfig podClientConfig,
                         final ClientConfig agentClientConfig) {
        this.config = configuration;
        this.symBotAuth = symBotAuthImp;
        this.podClient = ClientBuilder.newClient(podClientConfig); // Here
        this.agentClient = ClientBuilder.newClient(agentClientConfig); // Here
        try {
            botUserInfo = this.getUsersClient().getSessionUser();
        } catch (SymClientException e) {
            logger.error("Error getting sessionUser ", e);
        }
        SymMessageParser.createInstance(this);
    }
private SymBotClient(SymConfig config, ISymAuth symBotAuth) {
        this.config = config;
        this.symBotAuth = symBotAuth;

        if (isEmpty(config.getProxyURL())) {
            this.podClient = HttpClientBuilderHelper
                    .getHttpClientBuilderWithTruststore(config).build(); // Here
            this.agentClient = HttpClientBuilderHelper
                    .getHttpClientBuilderWithTruststore(config).build(); // Here
        } else {
            ClientConfig clientConfig = new ClientConfig();
            clientConfig.connectorProvider(new ApacheConnectorProvider());
            clientConfig.property(ClientProperties.PROXY_URI,
                    config.getProxyURL());
            if (config.getProxyUsername() != null
                    && config.getProxyPassword() != null) {
                clientConfig.property(ClientProperties.PROXY_USERNAME,
                        config.getProxyUsername());
                clientConfig.property(ClientProperties.PROXY_PASSWORD,
                        config.getProxyPassword());
            }
            this.agentClient = HttpClientBuilderHelper
                    .getHttpClientBuilderWithTruststore(config)
                    .withConfig(clientConfig).build();
            this.podClient =  HttpClientBuilderHelper
                    .getHttpClientBuilderWithTruststore(config)
                    .withConfig(clientConfig).build();
        }
        try {
            botUserInfo = this.getUsersClient().getSessionUser();
        }  catch (SymClientException e) {
            logger.error("Error getting sessionUser ", e);
        }
        SymMessageParser.createInstance(this);
    }

Is it possible to add specific properties for configuring the proxy for the pod and the agent separately?

Refs:

Module system

DRAFT, IN PROGRESS

The purpose of this issue is to introduce and specify a new module system for the BDK library. We want to empower contributors to create their own modules or plugins in separate repositories, without necessary having to make their contributions directly in the BDK codebase.

Overview

public class MyModule implements BdkModule, BdkLifecycleAware, BdkConfigurationAware {
  
  @Override // provided by BdkConfigurationAware
  public void onConfigurationSet(BdkConfig config) {}

  @Override // provided by BdkLifecycleAware
  public void onCoreInitialized(SymphonyBdk bdk) {}
}

Loading system

To explore:

SymphonyBdk bdk = new SymphonyBdkBuilder().config(config).withModule(MyModule.class).build();

Module Service

On the other hand, a developer should also be able to retrieve a module service, for instance using:

MyModuleService moduleService = bdk.lookupModuleService(MyModuleService.class); 

Datafeed stops on unhandled socketimeoutexception

An unhandled socketimeoutexception causes the process of trying to connect to Datafeed from time to time to stop. After that, the application needs to be restarted to get back to work. The exception trail is the following:

1- (DatafeedClient.java:45) builder.post(null) call throws SocketTimeoutException;
2- (DatafeedEventsService.java:228) SocketTimeoutException not unhandled by catch (SymClientException e1);
3- (DatafeedEventsService.java:173) SocketTimeoutException still unhandled, as it happens inside CompletableFuture.exceptionally() it will be wrapped in an ExecutionException
4- (DatafeedEventsService.java:185) catch ExecutionException and log it
5- bot stops to read Datafeed.

Fix suggestion:
Catch SocketTimeoutException on DatafeedClient.createDatafeed() and handle the same way as unsuccessful response (DatafeedClient.java:46).

No message body reader has been found for class model.Token

Looks like missing dependency problem, but i have the symphony-api-client-java:1.0.37 in the pom

Aug 16, 2019 4:29:11 AM org.apache.cxf.jaxrs.utils.JAXRSUtils logMessageHandlerProblem
SEVERE: No message body reader has been found for class model.Token, ContentType: application/json
Exception in thread "main" javax.ws.rs.client.ResponseProcessingException: No message body reader has been found for class model.Token, ContentType: application/json
	at org.apache.cxf.jaxrs.impl.ResponseImpl.reportMessageHandlerProblem(ResponseImpl.java:437)
	at org.apache.cxf.jaxrs.impl.ResponseImpl.doReadEntity(ResponseImpl.java:390)
	at org.apache.cxf.jaxrs.impl.ResponseImpl.readEntity(ResponseImpl.java:314)
	at org.apache.cxf.jaxrs.impl.ResponseImpl.readEntity(ResponseImpl.java:304)
	at authentication.SymBotAuth.sessionAuthenticate(SymBotAuth.java:120)
	at authentication.SymBotAuth.authenticate(SymBotAuth.java:75)

SlashAnnotationProcessor triggers BeanCreationException when there are request scoped beans defined

We are running into an issue where on spring boot application startup the SlashAnnotationProcessor tries to create all the beans in our project, and some of them cannot be created out of their defined scope or cannot be created through applicationContext.getBean().
This issue affects all versions up to 1.5.0.BETA
When the exception is thrown it prevents our application from starting up.
I have a minimal repro of the issue at https://github.com/putterson/symphony-spring-bug-repro

No message body reader has been found for class com.docusign.esign.client.auth.OAuth$OAuthToken

After updating our docusign dependency to 3.8.0 from 2.8.0 (we also attempted 2.9.0) I am finding that we are now seeing the title error popping up when making a request.

[2020.09.14 11:54:02.230 [localhost] ERROR http-nio-8080-exec-9 JAXRSUtils:1807] [GUID=3436fca3-aa37-43aa-87e9-47e199ca5d8a] No message body reader has been found for class com.docusign.esign.client.auth.OAuth$OAuthToken, ContentType: application/json;charset=utf-8
[2020.09.14 11:54:02.231 [localhost] ERROR http-nio-8080-exec-9 DocusignAuthenticationService:80] [GUID=3436fca3-aa37-43aa-87e9-47e199ca5d8a] Unknown error getting docusign access token
javax.ws.rs.client.ResponseProcessingException: No message body reader has been found for class com.docusign.esign.client.auth.OAuth$OAuthToken, ContentType: application/json;charset=utf-8
at org.apache.cxf.jaxrs.impl.ResponseImpl.reportMessageHandlerProblem(ResponseImpl.java:434) ~[cxf-rt-frontend-jaxrs-3.2.5.jar:3.2.5]
at org.apache.cxf.jaxrs.impl.ResponseImpl.doReadEntity(ResponseImpl.java:387) ~[cxf-rt-frontend-jaxrs-3.2.5.jar:3.2.5]

Nothing in the library call changed.

apiClient.requestJWTUserToken(configuration.getIntegratorKey(), configuration.getUserId(), DEFAULT_SCOPES, configuration.getPrivateKey().getBytes(), JWT_TOKEN_TIMEOUT)

While stepping through the execution of the auth I am seeing that the API itself returns a success response with the following (trimmed) block.

{"access_token":"itsasecretaccesstokensorrry","token_type":"Bearer","expires_in":3600}

Everything looks normal, but for some reason it is unable to map the JSON to the object after the request is made. Any suggestions or tweaks that might help alleviate this issue.

Using the gradle-gradle-plugin to download all licenses

As part of the FINOS Project Contribution, we need to validate all transitive licenses being distributed in the releases published in Maven Central.

I checked out this repo and added https://plugins.gradle.org/plugin/com.github.hierynomus.license-report to ./build.gradle:

buildscript {
    repositories {
        jcenter()
        mavenCentral()
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath 'io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.22.0'
        classpath "gradle.plugin.com.hierynomus.gradle.plugins:license-gradle-plugin:0.15.0"
    }
}

apply plugin: 'io.codearte.nexus-staging'
apply plugin: "com.github.hierynomus.license-report"

When I run gradle downloadLicenses I see that ./build/license-dependency.html is created (at root level), but not for all sub modules; could you help me understanding how to apply this command also for sub modules?

When this works, we could add a CircleCI task the continuously checks for suspicious or unknown licenses across all transitive dependencies.

Thanks in advance!

HttpClient NPE bug when add queryparam

Bug Report

When we try to add a query param to a HttpClient instance, a NPE will be thrown because the queryParams in RequestConfig was initialised with null and same for headers, cookies and formParams.
Ref

Steps to Reproduce:

Reproduce with the unittest:

final HttpClient httpClient = HttpClient.builder(this::mockedApiClientBuilder)
      .basePath("https://localhost:8080")
      .header("Connection", "Keep-Alive")
      .header("Keep-Alive", "timeout=5, max=1000")
      .cookie("foo", "bar")
      .build();

httpClient.queryParam("test", "test");

Expected Result:

The query param is added successfully.
Same for headers, cookies, formParams

Actual Result:

java.lang.NullPointerException
	at com.symphony.bdk.http.api.HttpClient$RequestConfig.appendQueryParam(HttpClient.java:394)
	at com.symphony.bdk.http.api.HttpClient.queryParam(HttpClient.java:182)
	at com.symphony.bdk.http.api.HttpClientTest.usage(HttpClientTest.java:22)

Environment:

symphony-bdk-2.1.0

RSA Auth to Extension Apps

As a team that uses the java-client in all bot projects, we would be able to authenticate the extension app using RSA certificates.
Today we can use regular certs to do it, but on R53 was released RSA authentication to extension apps that is so much better.

Keep Alive strategy configuration for ApiClient

Feature Request

As BDK ApiClient user, I'd like to be able to configure the keep alive strategy on the ApiClient.

Description of Problem:

The current BDK ApiClient does not allow users to configure the KeepAlive strategy on the Jersey ApiClient implementation, such feature allows to have a better throughout in a high load situation.

...please resist the temptation to describe your request in terms of a solution. Job Story form ("When [triggering condition], I want to [motivation/goal], so I can [outcome].") can help ensure you're expressing a problem statement.

Potential Solutions:

...clearly and concisely describe what you want to happen. Add any considered drawbacks.

... if you've considered alternatives, clearly and concisely describe those too.

SymBotRSAAuth: avoid inifinite loop if error during authentication

Hello,

If there is an error during SymBotRSAAuth.sessionAuthenticate, we get an infinite loop (i.e. let's imagine I have a proxy that returns 407 because of bad credentials, sessionAuthenticate will call endlessly.

Having a way to setup a max number of attempts before throwing the error would be nice

Provide base package

Organize the existing packages under the same base package (e.g. org.symphony).
This is important for troubleshooting applications using the Symphony API client as it would make easier for setting log level just for the Symphony API client.

Initialise DistributedTracingContext in AbstractActivity

Feature Request

DistributedTracingContext is initialised for the rest api request today, i would like to have the same traceability for the activities.

Description of Problem:

When BOT receives a message from DF, i'd like to the traceability as we do in the rest api.

Potential Solutions:

Initialise the DistributedTracingContext at the start point of the #processEvent.

... if you've considered alternatives, clearly and concisely describe those too.

SymExtensionAppRSAAuth only supports app RSA key specified in SymConfig

SymExtensionAppRSAAuth only allows to specify the app RSA key in SymConfig as a path to the RSA file. This is an issue in case the RSA key is hosted somewhere not reachable by the supported SymConfig path. Or if the RSA key is generated on the fly.

A more flexible way, to complement SymConfig, is to pass to SymExtensionAppRSAAuth a PrivateKey object so that SymExtensionAppRSAAuth does not need to worry to support all possible ways a private key is fetched.

lb-config.json is ignored

I have specified a lb-config.json and it says in the logs "Loading load balancer config from:/data/web/apps/jira/lb-config.json" but it still uses the agent specified in config.json

Connection pooling with BDK 2.0

Hi,
I'm having some issues using the Symphony BDK that I'd like to seek some support with.
In a nutshell, I'm using BDK 2.0 to create a bridge to allow 3rd party tools to send alerts via Symphony to appropriate users/rooms. Its a spring boot app exposing rest end points for services to send alert messages.

All works well for a while, but will fail after a period of time to send messages. Sometimes it can be hours other times weeks.
We do connect through a proxy which may have a part in this, but it seems the issue is around PoolingHttpClientConnectionManager.
I see a debug message stating PoolingHttpClientConnectionManager Connection request [route: {tls}->[proxy server] -> ***.symphony.com:443][Total available: 0; route allocated: 2 of 2; total allocated: 2 of 20]. Seems to suggest that there are no connections available in the pool? Not being released back? Is there perhaps a way I can configure TTL to expire after a few minutes for example to release the connection back to the pool?

I've seen the issue with SDK versions and now updated to the latest BDK 2.0 in the hope it might be resolved.
AS mentioned, this might be something to do with the proxy server, but thought worth starting a dialogue in case its a known issue?

Is this a common problem and any suggestions to prevent? Any assistance greatly appreciated.

๐Ÿ”ซ Bulletproof DatafeedLoop

Context

One the most important feature of the BDK is certainly the Datafeed Loop that allows your bot application to receive Real Time Events. The health of your bot strongly depends on this DF Loop. A broken DF Loop means that your bot cannot receive chat events and therefore cannot properly works.

Problem

When using the Spring Boot wrapper, the DF Loop is executed as a separate thread in order to not block the main thread. This is quite different for a pure Java application, when the DF Loop is usually started as part of the main thread and blocks this one until the loop (e.g. while(true) { readDatafeed(); } is still running).

We already implemented a dedicated datafeed retry strategy that can be configured as such:

# config.yaml
datafeed:
  retry:
    maxAttempts: 6
    initialIntervalMillis: 2000
    multiplier: 1.5
    maxIntervalMillis: 10000

Reaching the maxAttempts value means that the loop will exit and thus its thread will stop as well. Causing an unrecoverable state for your bot application.

โ“ We would like to figure out what could be the best strategy to handle this bad situation, when your container is still alive but the DF Loop has crashed making your bot application unusable.

Proposed solution

One of the most straightforward solution that came to our mind is to make maxAttemps value almost infinite (e.g. equals to Integer.MAX_VALUE). Depending on the others retry parameters (initialIntervalMillis, multiplier and maxIntervalMillis) this would make the loop retrying for several years, so let's say forever!

Limitations

Config issue

Let's imagine that your BDK config contains an issue (for instance a wrong pod url). Your container successfully starts up but the DF Loop directly starts retrying forever, making your container-orchestrator unable to detect any issue.

Project update following transfer to FINOS

Now the project has been transferred FINOS, we need to update some stuffs in the code related to the previous location. It will include:

  • links in README.md
  • Maven coordinates (from com.symphony.platformsolutions to org.finos.symphony.bdk)
  • CICD (from CircleCI/Jenkins to Github actions)

How to call logout from SymphonyBdk

Hello, I am not sure is it good to post question here.

I would like to know is is it possible to call logout from SymphonyBdk class?

I found we can call logout from ISymAuth, but seems I cannot find any linkage between SymphonyBdk with ISymAuth.

Thank you very much.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.