Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

APP-2908: Fluent API setup #205

Merged
merged 9 commits into from
Sep 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion docs/authentication.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
# Authentication

To be done...
## Bot authentication

To be updated...

## OBO authenticating using SymphonyBdk

On Behalf Of (OBO) is a pattern that enables developers to perform operations on behalf of a Symphony end-user. [`Getting started with OBO](https://developers.symphony.com/restapi/docs/get-started-with-obo)

With a [`SymphonyBdk`](../symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java) instance, we can easily authenticate the bot in OBO mode:

```java
public class Example {

public static void main(String[] args) {
// Initialize the BDK entry point
final SymphonyBdk bdk = new SymphonyBdk(loadFromClasspath("config.yaml"));
// OBO authentication
AuthSession oboSession = bdk.obo("user.name");
// Running service in Obo mode
final List<V2UserDetail> userDetails = bdk.users().listUsersDetail(new UserFilter(), oboSession);
}
}

```
51 changes: 51 additions & 0 deletions docs/fluent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Fluent API

The Fluent API is the most basic feature of the BDK. This component provides the developers very quickly an entry point
to discover all others features of the BDK, helps them to easily understand how to make a bot interacting with the
Symphony platform.

## SymphonyBdk

The heart of the Fluent API is the [`SymphonyBdk`](../symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java).
This component is an entry point for a developer to go through all the features of the BDK. A `SymphonyBdk` object is
built from the information extracted from the BDK configuration file.

```java
public class Example {

public static void main(String[] args) {
// Initialize the BDK entry point
final SymphonyBdk bdk = new SymphonyBdk(loadFromClasspath("config.yaml"));
}
}
```


## Using BDK services from SymphonyBdk

Once the `SymphonyBdk` instance is created, the bot is automatically authenticated and all the BDK services will be available
for developers to use.

```java
public class Example {

public static void main(String[] args) {
// Initialize the BDK entry point
final SymphonyBdk bdk = new SymphonyBdk(loadFromClasspath("config.yaml"));
// Using users service
final List<V2UserDetail> userDetails = bdk.users().listUsersDetail(new UserFilter());
// Using datafeed service
bdk.datafeed().start();
}
}
```

Developers can use the services provided by the BDK by calling the method with the name of the service. For the moment, the services
that is available in BDK is:

- Users Service: `bdk.users()`
- Streams Service: `bdk.streams()`
- Message Service: `bdk.messages()`
- Datafeed Service: `bdk.datafeed()`
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved
- Activities Registry: `bdk.activities()`

10 changes: 5 additions & 5 deletions symphony-bdk-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<artifactId>symphony-bdk-core-invoker-jersey2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.symphony.platformsolutions</groupId>
<artifactId>symphony-bdk-template-freemarker</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

Expand Down Expand Up @@ -245,11 +250,6 @@
<exclude>com/symphony/bdk/core/**/*Exception.class</exclude>
<exclude>com/symphony/bdk/core/**/model/*.class</exclude>

<!-- Exclude Thibault's temporary classes from coverage -->
<exclude>com/symphony/bdk/core/SymphonyBdk.class</exclude>
<exclude>com/symphony/bdk/core/service/Obo.class</exclude>
<exclude>com/symphony/bdk/core/service/Obo$Handle.class</exclude>

<!-- We don't cover generated code -->
<exclude>com/symphony/bdk/gen/**/*</exclude>
</excludes>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package com.symphony.bdk.core;

import com.symphony.bdk.core.api.invoker.ApiClient;
import com.symphony.bdk.core.auth.AuthSession;
import com.symphony.bdk.core.config.model.BdkConfig;
import com.symphony.bdk.core.service.MessageService;
import com.symphony.bdk.core.service.SessionService;
import com.symphony.bdk.core.service.datafeed.DatafeedService;
import com.symphony.bdk.core.service.datafeed.DatafeedVersion;
import com.symphony.bdk.core.service.datafeed.impl.DatafeedServiceV1;
import com.symphony.bdk.core.service.datafeed.impl.DatafeedServiceV2;
import com.symphony.bdk.core.service.stream.StreamService;
import com.symphony.bdk.core.service.user.UserService;
import com.symphony.bdk.gen.api.AttachmentsApi;
import com.symphony.bdk.gen.api.DatafeedApi;
import com.symphony.bdk.gen.api.DefaultApi;
import com.symphony.bdk.gen.api.MessageApi;
import com.symphony.bdk.gen.api.MessageSuppressionApi;
import com.symphony.bdk.gen.api.MessagesApi;
import com.symphony.bdk.gen.api.PodApi;
import com.symphony.bdk.gen.api.SessionApi;
import com.symphony.bdk.gen.api.StreamsApi;
import com.symphony.bdk.gen.api.UserApi;
import com.symphony.bdk.gen.api.UsersApi;

import org.apiguardian.api.API;

/**
* Factory responsible for creating BDK service instances for Symphony Bdk entry point.
* :
* <ul>
* <li>{@link UserService}</li>
* <li>{@link StreamService}</li>
* <li>{@link MessageService}</li>
* <li>{@link DatafeedService}</li>
* <li>{@link SessionService}</li>
* </ul>
*/
@API(status = API.Status.INTERNAL)
class ServiceFactory {
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved

private final ApiClient podClient;
private final ApiClient agentClient;
private final AuthSession authSession;
private final BdkConfig config;

public ServiceFactory(ApiClient podClient, ApiClient agentClient, AuthSession authSession, BdkConfig config) {
this.podClient = podClient;
this.agentClient = agentClient;
this.authSession = authSession;
this.config = config;
}

/**
* Returns a fully initialized {@link UserService}.
*
* @return an new {@link UserService} instance.
*/
public UserService getUserService() {
return new UserService(new UserApi(podClient), new UsersApi(podClient), authSession );
}

/**
* Returns a fully initialized {@link StreamService}.
*
* @return an new {@link StreamService} instance.
*/
public StreamService getStreamService() {
return new StreamService(new StreamsApi(podClient), authSession);
}

/**
* Returns a fully initialized {@link SessionService}.
*
* @return an new {@link SessionService} instance.
*/
public SessionService getSessionService() {
return new SessionService(new SessionApi(podClient));
}

/**
* Returns a fully initialized {@link DatafeedService}.
*
* @return an new {@link DatafeedService} instance.
*/
public DatafeedService getDatafeedService() {
if (DatafeedVersion.of(config.getDatafeed().getVersion()) == DatafeedVersion.V2) {
return new DatafeedServiceV2(new DatafeedApi(agentClient), authSession, config);
}
return new DatafeedServiceV1(new DatafeedApi(agentClient), authSession, config);
}

/**
* Returns a fully initialized {@link MessageService}.
*
* @return an new {@link MessageService} instance.
*/
public MessageService getMessageService() {
return new MessageService(new MessagesApi(this.agentClient), new MessageApi(this.podClient),
new MessageSuppressionApi(this.podClient), new StreamsApi(this.podClient), new PodApi(this.podClient),
new AttachmentsApi(this.agentClient), new DefaultApi(this.podClient), this.authSession);
}
}
124 changes: 63 additions & 61 deletions symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.symphony.bdk.core;

import com.symphony.bdk.core.activity.ActivityRegistry;
import com.symphony.bdk.core.api.invoker.ApiClient;
import com.symphony.bdk.core.auth.AuthSession;
import com.symphony.bdk.core.auth.AuthenticatorFactory;
import com.symphony.bdk.core.auth.OboAuthenticator;
Expand All @@ -10,28 +9,12 @@
import com.symphony.bdk.core.client.ApiClientFactory;
import com.symphony.bdk.core.config.model.BdkConfig;
import com.symphony.bdk.core.service.MessageService;
import com.symphony.bdk.core.service.Obo;
import com.symphony.bdk.core.service.SessionService;
import com.symphony.bdk.core.service.datafeed.DatafeedService;
import com.symphony.bdk.core.service.datafeed.DatafeedVersion;
import com.symphony.bdk.core.service.datafeed.impl.DatafeedServiceV1;
import com.symphony.bdk.core.service.datafeed.impl.DatafeedServiceV2;
import com.symphony.bdk.core.service.stream.StreamService;
import com.symphony.bdk.core.service.user.UserService;
import com.symphony.bdk.gen.api.AttachmentsApi;
import com.symphony.bdk.gen.api.DatafeedApi;
import com.symphony.bdk.gen.api.DefaultApi;
import com.symphony.bdk.gen.api.MessageApi;
import com.symphony.bdk.gen.api.MessageSuppressionApi;
import com.symphony.bdk.gen.api.MessagesApi;

import com.symphony.bdk.gen.api.PodApi;
import com.symphony.bdk.gen.api.SessionApi;
import com.symphony.bdk.gen.api.StreamsApi;
import com.symphony.bdk.gen.api.UserApi;

import com.symphony.bdk.gen.api.UsersApi;

import lombok.Generated;
import lombok.extern.slf4j.Slf4j;
import org.apiguardian.api.API;

Expand All @@ -44,60 +27,59 @@
@API(status = API.Status.EXPERIMENTAL)
public class SymphonyBdk {

private final ApiClientFactory apiClientFactory;
private final ApiClient podClient;
private final ApiClient agentClient;

private final AuthSession botSession;
private final OboAuthenticator oboAuthenticator;

private final DatafeedService datafeedService;
private final UserService userService;
private final StreamService streamService;
private final SessionService sessionService;
private final ActivityRegistry activityRegistry;
private final SessionService sessionService;
private final StreamService streamService;
private final UserService userService;
private final MessageService messageService;
private final DatafeedService datafeedService;

@Generated
public SymphonyBdk(BdkConfig config) throws AuthInitializationException, AuthUnauthorizedException {
ApiClientFactory apiClientFactory = new ApiClientFactory(config);
final AuthenticatorFactory authenticatorFactory = new AuthenticatorFactory(config, apiClientFactory);
AuthSession botSession = authenticatorFactory.getBotAuthenticator().authenticateBot();
this.oboAuthenticator = config.isOboConfigured() ? authenticatorFactory.getOboAuthenticator() : null;
ServiceFactory serviceFactory =
new ServiceFactory(apiClientFactory.getPodClient(), apiClientFactory.getAgentClient(), botSession, config);

// service init
this.sessionService = serviceFactory.getSessionService();
this.userService = serviceFactory.getUserService();
this.streamService = serviceFactory.getStreamService();
this.messageService = serviceFactory.getMessageService();
this.datafeedService = serviceFactory.getDatafeedService();
thibauult marked this conversation as resolved.
Show resolved Hide resolved

// setup activities
this.activityRegistry = new ActivityRegistry(this.sessionService.getSession(botSession), this.datafeedService::subscribe);
}

this.apiClientFactory = new ApiClientFactory(config);
this.podClient = apiClientFactory.getPodClient();
this.agentClient = apiClientFactory.getAgentClient();

final AuthenticatorFactory authenticatorFactory = new AuthenticatorFactory(config, this.apiClientFactory);

this.botSession = authenticatorFactory.getBotAuthenticator().authenticateBot();
protected SymphonyBdk(BdkConfig config, ServiceFactory serviceFactory, AuthenticatorFactory authenticatorFactory)
throws AuthInitializationException, AuthUnauthorizedException {
AuthSession botSession = authenticatorFactory.getBotAuthenticator().authenticateBot();
this.oboAuthenticator = config.isOboConfigured() ? authenticatorFactory.getOboAuthenticator() : null;

// setup the datafeed
final DatafeedApi datafeedApi = new DatafeedApi(this.agentClient);
if (DatafeedVersion.of(config.getDatafeed().getVersion()) == DatafeedVersion.V2) {
this.datafeedService = new DatafeedServiceV2(datafeedApi, this.botSession, config);
} else {
this.datafeedService = new DatafeedServiceV1(datafeedApi, this.botSession, config);
}
// setup other services
this.userService = new UserService(new UserApi(this.podClient), new UsersApi(this.podClient), this.botSession);
this.streamService = new StreamService(new StreamsApi(this.podClient), this.botSession);
this.sessionService = new SessionService(new SessionApi(this.podClient));
this.activityRegistry = new ActivityRegistry(this.sessionService.getSession(this.botSession), this.datafeedService::subscribe);
}
// service init
this.sessionService = serviceFactory.getSessionService();
this.userService = serviceFactory.getUserService();
this.streamService = serviceFactory.getStreamService();
this.messageService = serviceFactory.getMessageService();
this.datafeedService = serviceFactory.getDatafeedService();

public MessageService messages() {
return new MessageService(new MessagesApi(this.agentClient), new MessageApi(this.podClient),
new MessageSuppressionApi(this.podClient), new StreamsApi(this.podClient), new PodApi(this.podClient),
new AttachmentsApi(this.agentClient), new DefaultApi(this.podClient), this.botSession);
// setup activities
this.activityRegistry = new ActivityRegistry(this.sessionService.getSession(botSession), this.datafeedService::subscribe);
}

public MessageService messages(Obo.Handle oboHandle) throws AuthUnauthorizedException {
AuthSession oboSession;
if (oboHandle.hasUsername()) {
oboSession = this.getOboAuthenticator().authenticateByUsername(oboHandle.getUsername());
} else {
oboSession = this.getOboAuthenticator().authenticateByUserId(oboHandle.getUserId());
}
return new MessageService(new MessagesApi(this.agentClient), new MessageApi(this.podClient),
new MessageSuppressionApi(this.podClient), new StreamsApi(this.podClient), new PodApi(this.podClient),
new AttachmentsApi(this.agentClient), new DefaultApi(this.podClient), oboSession);
/**
* Get the {@link MessageService} from a Bdk entry point.
* The returned message service instance.
*
* @return {@link MessageService} message service instance.
*/
public MessageService messages() {
return this.messageService;
}

/**
Expand Down Expand Up @@ -137,6 +119,26 @@ public ActivityRegistry activities() {
return this.activityRegistry;
}

/**
* OBO Authenticate by using user Id.
*
* @param id User id
* @return Obo authentication session
*/
public AuthSession obo(Long id) throws AuthUnauthorizedException {
return this.getOboAuthenticator().authenticateByUserId(id);
}

/**
* OBO Authenticate by using username.
*
* @param username Username
* @return Obo authentication session
*/
public AuthSession obo(String username) throws AuthUnauthorizedException {
return this.getOboAuthenticator().authenticateByUsername(username);
}

protected OboAuthenticator getOboAuthenticator() {
return Optional.ofNullable(this.oboAuthenticator)
.orElseThrow(() -> new IllegalStateException("OBO is not configured."));
Expand Down
Loading