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-3073: Enhancements on MessageService #277

Merged
merged 18 commits into from
Oct 9, 2020
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
214d830
Add internal dependencies version to bom module
symphony-hong Oct 1, 2020
4220b9c
Update missing dependencies
symphony-hong Oct 2, 2020
a9c2f47
Merge branch 'master' of https://github.com/SymphonyPlatformSolutions…
symphony-hong Oct 5, 2020
b3ad26d
Adding plugin to http and template submodule
symphony-hong Oct 5, 2020
72bb76c
Ability to directly set privateKey and certificate content
symphony-hong Oct 6, 2020
ca67543
Merge branch 'master' of https://github.com/SymphonyPlatformSolutions…
symphony-hong Oct 6, 2020
8991945
Fix typo and add documentation
symphony-hong Oct 6, 2020
ba7cef6
Update documentation
symphony-hong Oct 6, 2020
ca0035c
Enhancements on message service
symphony-hong Oct 7, 2020
8503e8f
Merge branch 'master' of https://github.com/SymphonyPlatformSolutions…
symphony-hong Oct 7, 2020
98c3b3d
Merge branch 'master' into APP-3073
symphony-hong Oct 7, 2020
fbe6676
Create message and attachment model to use in MessageService
symphony-hong Oct 8, 2020
edd4225
Merge branch 'master' of https://github.com/SymphonyPlatformSolutions…
symphony-hong Oct 8, 2020
b99a085
Merge branch 'APP-3073' of github.com:symphony-hong/symphony-api-clie…
symphony-hong Oct 8, 2020
09b9aef
Refactor MessageService and update unittest
symphony-hong Oct 8, 2020
865bf89
Provide MessageService#builder to build a message instance from Messa…
symphony-hong Oct 9, 2020
5fba2fa
Merge branch 'master' into APP-3073
symphony-hong Oct 9, 2020
d837eda
Update handling attachments
symphony-hong Oct 9, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.symphony.bdk.core.client.ApiClientFactory;
import com.symphony.bdk.core.config.model.BdkConfig;
import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder;
import com.symphony.bdk.core.service.MessageService;
import com.symphony.bdk.core.service.message.MessageService;
thibauult marked this conversation as resolved.
Show resolved Hide resolved
import com.symphony.bdk.core.service.SessionService;
import com.symphony.bdk.core.service.datafeed.DatafeedService;
import com.symphony.bdk.core.service.datafeed.DatafeedVersion;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import com.symphony.bdk.core.auth.exception.AuthUnauthorizedException;
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.message.MessageService;
import com.symphony.bdk.core.service.SessionService;
import com.symphony.bdk.core.service.datafeed.DatafeedService;
import com.symphony.bdk.core.service.stream.StreamService;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.symphony.bdk.core.service;
package com.symphony.bdk.core.service.message;


import com.symphony.bdk.core.auth.AuthSession;
import com.symphony.bdk.core.retry.RetryWithRecovery;
import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder;
import com.symphony.bdk.core.service.message.exception.MessageCreationException;
import com.symphony.bdk.core.service.message.model.Attachment;
import com.symphony.bdk.core.service.message.model.Message;
import com.symphony.bdk.core.service.pagination.PaginatedApi;
import com.symphony.bdk.core.service.pagination.PaginatedService;
import com.symphony.bdk.core.service.stream.constant.AttachmentSort;
Expand All @@ -27,12 +30,14 @@
import com.symphony.bdk.gen.api.model.V4Stream;
import com.symphony.bdk.http.api.util.ApiUtils;
import com.symphony.bdk.template.api.TemplateEngine;
import com.symphony.bdk.template.api.TemplateException;
import com.symphony.bdk.template.api.TemplateResolver;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apiguardian.api.API;

import java.io.File;
import java.io.IOException;
import java.time.Instant;
import java.util.List;
import java.util.stream.Stream;
Expand Down Expand Up @@ -165,59 +170,67 @@ public Stream<V4Message> getMessagesStream(@Nonnull String streamId, @Nonnull In
* @return a {@link V4Message} object containing the details of the sent message
* @see <a href="https://developers.symphony.com/restapi/reference#create-message-v4">Create Message v4</a>
*/
@Deprecated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Javadoc @deprecated tag to mention that this method will be replaced by send(V4Stream, Message)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not we remove it at once since we are in beta?

public V4Message send(@Nonnull V4Stream stream, @Nonnull String message) {
return send(stream.getStreamId(), message);
}

/**
* Sends a templated to the stream ID of the passed {@link V4Stream} object.
* Sends a message to the stream ID passed in parameter.
*
* @param stream the stream to send the message to
* @param template the template name to be used to produce the message
* @param parameters the parameters to pass to the template to produce the message to be sent
* @param streamId the ID of the stream to send the message to
* @param message the message payload in MessageML
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved
* @return a {@link V4Message} object containing the details of the sent message
* @see <a href="https://developers.symphony.com/restapi/reference#create-message-v4">Create Message v4</a>
*/
public V4Message send(@Nonnull V4Stream stream, @Nonnull String template, Object parameters)
throws TemplateException {
return send(stream.getStreamId(), templateResolver.resolve(template).process(parameters));
}

/**
* Sends a templated to the stream ID passed in parameter.
*
* @param streamId the ID of the stream to send the message to
* @param template the template name to be used to produce the message
* @param parameters the parameters to pass to the template to produce the message to be sent
* @return a {@link V4Message} object containing the details of the sent message
* @throws TemplateException
*/
public V4Message send(@Nonnull String streamId, @Nonnull String template, Object parameters)
throws TemplateException {
return send(streamId, templateResolver.resolve(template).process(parameters));
@Deprecated
public V4Message send(@Nonnull String streamId, @Nonnull String message) {
return executeAndRetry("send", () -> messagesApi.v4StreamSidMessageCreatePost(
streamId,
authSession.getSessionToken(),
authSession.getKeyManagerToken(),
message,
null,
null,
null,
null
));
}

/**
* Sends a message to the stream ID passed in parameter.
*
* @param streamId the ID of the stream to send the message to
* @param message the message payload in MessageML
* @param streamId the ID of the stream to send the message to
* @param message the message to send to the stream
* @return a {@link V4Message} object containing the details of the sent message
* @see <a href="https://developers.symphony.com/restapi/reference#create-message-v4">Create Message v4</a>
*/
public V4Message send(@Nonnull String streamId, @Nonnull String message) {
public V4Message send(@Nonnull String streamId, @Nonnull Message message) {
File tempFile = this.createTemporaryAttachmentFile(message.getAttachment());
return executeAndRetry("send", () -> messagesApi.v4StreamSidMessageCreatePost(
streamId,
authSession.getSessionToken(),
authSession.getKeyManagerToken(),
message,
null,
null,
message.getContent(),
message.getData(),
null,
tempFile,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.createTemporaryAttachmentFile(message.getAttachment()) directly here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know why yet but if I use this.createTemporaryAttachmentFile(message.getAttachment()), method will throw a RuntimeException instead of MessageCreationException and the unittest will fail

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because the retry throws every Throwable as RuntimeException

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And I would create the temp file outside the retry to avoid new file created if the retry recovery is triggered

null
));
}

/**
* Sends a message to the stream ID passed in parameter.
*
* @param stream the stream to send the message to
* @param message the message to send to the stream
* @return a {@link V4Message} object containing the details of the sent message
* @see <a href="https://developers.symphony.com/restapi/reference#create-message-v4">Create Message v4</a>
*/
public V4Message send(@Nonnull V4Stream stream, @Nonnull Message message) {
return send(stream.getStreamId(), message);
}

/**
* Downloads the attachment body by the stream ID, message ID and attachment ID.
*
Expand Down Expand Up @@ -386,4 +399,22 @@ private static Long getEpochMillis(Instant instant) {
private <T> T executeAndRetry(String name, SupplierWithApiException<T> supplier) {
return RetryWithRecovery.executeAndRetry(retryBuilder, name, supplier);
}

private File createTemporaryAttachmentFile(Attachment attachment) {
if (attachment == null) {
return null;
}
try {
String[] fileNameArrays = attachment.fileName().split("\\.");
if (fileNameArrays.length < 2) {
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved
throw new MessageCreationException("Invalid attachment's file name.");
}
File tempFile = File.createTempFile(fileNameArrays[0], "." + fileNameArrays[fileNameArrays.length - 1]);
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved
tempFile.deleteOnExit();
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved
FileUtils.copyInputStreamToFile(attachment.inputStream(), tempFile);
return tempFile;
} catch (IOException e) {
throw new MessageCreationException("Cannot create attachment.", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.symphony.bdk.core.service.message.exception;

import org.apiguardian.api.API;

/**
* Exception thrown when a {@link com.symphony.bdk.core.service.message.model.Message} is failed to create.
*/
@API(status = API.Status.EXPERIMENTAL)
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved
public class MessageCreationException extends RuntimeException {

public MessageCreationException(String message, Exception e) {
super(message, e);
}

public MessageCreationException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.symphony.bdk.core.service.message.model;

import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.apiguardian.api.API;

import java.io.InputStream;

@Getter
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved
@Setter
@Accessors(fluent = true)
@API(status = API.Status.EXPERIMENTAL)
public class Attachment {

private InputStream inputStream;
private String fileName;
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.symphony.bdk.core.service.message.model;

import lombok.Getter;
import lombok.Setter;
import org.apiguardian.api.API;

@Getter
@Setter
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved
@API(status = API.Status.EXPERIMENTAL)
public class Message {
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved

private String content;
private String data;
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved
private Attachment attachment;

protected Message(MessageBuilder builder) {
this.content = builder.content();
this.data = builder.data();
this.attachment = builder.attachment();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.symphony.bdk.core.service.message.model;

import static java.util.Collections.emptyMap;

import com.symphony.bdk.core.service.message.exception.MessageCreationException;
import com.symphony.bdk.template.api.Template;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.apiguardian.api.API;

/**
* Builder for {@link Message}.
* Allows configuring the field of the messages before constructing them with build()
*/
@Getter
@Setter
@Accessors(fluent = true)
@API(status = API.Status.EXPERIMENTAL)
public class MessageBuilder {

private static final ObjectMapper MAPPER = new JsonMapper();

private String version = "2.0";
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved
private String content;
private String data;
private Attachment attachment;

private MessageBuilder() {

}

/**
* Create a builder from a MessageML content.
* @param message MessageML content
* @return MessageBuilder with the MessageML content
*/
public static MessageBuilder fromMessageMl(String message) {
return new MessageBuilder().content(message);
}

/**
* Create a builder from a Template and parameters.
* @param template a custom or built-in message template.
* @return MessageBuilder with the MessageML content generated from the template with the passed parameters.
*/
public static MessageBuilder fromTemplate(Template template, Object parameters) {
return new MessageBuilder().content(template.process(parameters));
}

/**
* Create a builder from a static Template with no parameter.
* @param template a custom or built-in message template.
* @return MessageBuilder with the MessageML content generated from the template.
*/
public static MessageBuilder fromTemplate(Template template) {
return new MessageBuilder().content(template.process(emptyMap()));
}

/**
* Add data to the message.
* @param data Serializable data object.
* @return this builder with the data configured.
*/
public MessageBuilder data(Object data) {
symphony-hong marked this conversation as resolved.
Show resolved Hide resolved
try {
this.data = MAPPER.writeValueAsString(data);
return this;
} catch (JsonProcessingException e) {
throw new MessageCreationException("Failed to parse data to Json string", e);
}
}

/**
* Create a {@link Message} using the configuration within the builder.
* @return constructed {@link Message} using configuration within this builder.
*/
public Message build() {
return new Message(this);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import com.symphony.bdk.core.config.model.BdkConfig;

import com.symphony.bdk.core.config.model.BdkDatafeedConfig;
import com.symphony.bdk.core.service.MessageService;
import com.symphony.bdk.core.service.message.MessageService;
import com.symphony.bdk.core.service.SessionService;
import com.symphony.bdk.core.service.datafeed.DatafeedService;
import com.symphony.bdk.core.service.datafeed.impl.DatafeedServiceV1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import com.symphony.bdk.core.config.BdkConfigLoader;
import com.symphony.bdk.core.config.exception.BdkConfigException;
import com.symphony.bdk.core.config.model.BdkConfig;
import com.symphony.bdk.core.service.MessageService;
import com.symphony.bdk.core.service.message.MessageService;
import com.symphony.bdk.core.service.datafeed.DatafeedService;
import com.symphony.bdk.core.service.datafeed.impl.DatafeedServiceV1;
import com.symphony.bdk.core.service.stream.StreamService;
Expand Down
Loading