From b8097ea24f621d72c2047de76a7d04e343633ae3 Mon Sep 17 00:00:00 2001 From: xiaoweii Date: Sat, 9 Sep 2023 08:30:16 +0800 Subject: [PATCH 1/8] feat: add set item api --- .../clickstream/AWSClickstreamPlugin.java | 14 +- .../clickstream/ClickstreamEvent.java | 29 +++- .../solution/clickstream/ClickstreamItem.java | 145 ++++++++++++++++++ .../clickstream/client/AnalyticsClient.java | 4 +- .../clickstream/client/AnalyticsEvent.java | 31 +++- .../solution/clickstream/client/Event.java | 129 ++++------------ .../clickstream/client/EventChecker.java | 127 +++++++++++++++ .../solution/clickstream/IntegrationTest.java | 35 +++++ 8 files changed, 399 insertions(+), 115 deletions(-) create mode 100644 clickstream/src/main/java/software/aws/solution/clickstream/ClickstreamItem.java create mode 100644 clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java diff --git a/clickstream/src/main/java/software/aws/solution/clickstream/AWSClickstreamPlugin.java b/clickstream/src/main/java/software/aws/solution/clickstream/AWSClickstreamPlugin.java index 22b7f2a..0a1b565 100644 --- a/clickstream/src/main/java/software/aws/solution/clickstream/AWSClickstreamPlugin.java +++ b/clickstream/src/main/java/software/aws/solution/clickstream/AWSClickstreamPlugin.java @@ -95,16 +95,16 @@ public void recordEvent(@NonNull String eventName) { @Override public void recordEvent(@NonNull AnalyticsEventBehavior analyticsEvent) { + ClickstreamEvent event = (ClickstreamEvent) analyticsEvent; final AnalyticsEvent clickstreamEvent = - analyticsClient.createEvent(analyticsEvent.getName()); + analyticsClient.createEvent(event.getName()); - if (analyticsEvent.getProperties() != null) { - for (Map.Entry> entry : analyticsEvent.getProperties()) { - AnalyticsPropertyBehavior property = entry.getValue(); - clickstreamEvent.addAttribute(entry.getKey(), property.getValue()); - } - analyticsClient.recordEvent(clickstreamEvent); + for (Map.Entry> entry : event.getProperties()) { + AnalyticsPropertyBehavior property = entry.getValue(); + clickstreamEvent.addAttribute(entry.getKey(), property.getValue()); } + clickstreamEvent.addItems(event.getItems()); + analyticsClient.recordEvent(clickstreamEvent); } @Override diff --git a/clickstream/src/main/java/software/aws/solution/clickstream/ClickstreamEvent.java b/clickstream/src/main/java/software/aws/solution/clickstream/ClickstreamEvent.java index b2d8d86..86559d5 100644 --- a/clickstream/src/main/java/software/aws/solution/clickstream/ClickstreamEvent.java +++ b/clickstream/src/main/java/software/aws/solution/clickstream/ClickstreamEvent.java @@ -44,10 +44,12 @@ public final class ClickstreamEvent implements AnalyticsEventBehavior { private static final int MAX_VALUE_LENGTH = 1024; private final String name; private final AnalyticsProperties properties; + private final ClickstreamItem[] items; - private ClickstreamEvent(String name, AnalyticsProperties properties) { + private ClickstreamEvent(String name, AnalyticsProperties properties, ClickstreamItem[] items) { this.name = name; this.properties = properties; + this.items = items; } /** @@ -72,6 +74,16 @@ public AnalyticsProperties getProperties() { return properties; } + /** + * Returns the {@link ClickstreamItem} array of the event. + * + * @return The {@link ClickstreamItem} array of the event + */ + @NonNull + public ClickstreamItem[] getItems() { + return items; + } + /** * Returns a new {@link Builder} to configure an instance of ClickstreamEvent. * @@ -92,6 +104,7 @@ public static Builder builder() { public static final class Builder { private String name; private AnalyticsProperties.Builder propertiesBuilder; + private ClickstreamItem[] items; /** * the builder for add event attribute. @@ -181,6 +194,18 @@ public Builder add(@NonNull @Size(min = 1L, max = MAX_NAME_LENGTH) String name, return this; } + /** + * Adds items to the {@link ClickstreamEvent}. + * + * @param items The items of the event + * @return Current Builder instance, for fluent method chaining + */ + @NonNull + public Builder setItems(ClickstreamItem[] items) { + this.items = items; + return this; + } + /** * Returns the built {@link ClickstreamEvent}. * @@ -189,7 +214,7 @@ public Builder add(@NonNull @Size(min = 1L, max = MAX_NAME_LENGTH) String name, */ @NonNull public ClickstreamEvent build() { - return new ClickstreamEvent(name, propertiesBuilder.build()); + return new ClickstreamEvent(name, propertiesBuilder.build(), this.items); } } } diff --git a/clickstream/src/main/java/software/aws/solution/clickstream/ClickstreamItem.java b/clickstream/src/main/java/software/aws/solution/clickstream/ClickstreamItem.java new file mode 100644 index 0000000..7327ec0 --- /dev/null +++ b/clickstream/src/main/java/software/aws/solution/clickstream/ClickstreamItem.java @@ -0,0 +1,145 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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. + */ + +package software.aws.solution.clickstream; + +import androidx.annotation.NonNull; +import androidx.annotation.Size; + +import com.amplifyframework.analytics.AnalyticsBooleanProperty; +import com.amplifyframework.analytics.AnalyticsDoubleProperty; +import com.amplifyframework.analytics.AnalyticsIntegerProperty; +import com.amplifyframework.analytics.AnalyticsProperties; +import com.amplifyframework.analytics.AnalyticsStringProperty; + +import software.aws.solution.clickstream.client.Event; + +/** + * ClickstreamItem for item record. + */ +public class ClickstreamItem extends ClickstreamAttribute { + /** + * Constructor for init the ClickstreamItem. + * + * @param builder An instance of the builder with the desired properties set. + */ + protected ClickstreamItem(@NonNull Builder builder) { + super(builder); + } + + + /** + * Begins construction of an {@link ClickstreamItem} using a builder pattern. + * + * @return An {@link ClickstreamItem.Builder} instance + */ + @NonNull + public static Builder builder() { + return new ClickstreamItem.Builder(); + } + + /** + * Builder for the {@link ClickstreamItem} class. + */ + public static class Builder extends ClickstreamAttribute.Builder { + private final AnalyticsProperties.Builder builder = AnalyticsProperties.builder(); + + /** + * Adds a {@link AnalyticsStringProperty} to the {@link AnalyticsProperties} under + * construction. + * + * @param key A name for the property + * @param value A String to store in the property + * @return Current Builder instance, for fluent method chaining + */ + @NonNull + public ClickstreamItem.Builder add(@NonNull @Size(min = 1L, max = Event.Limit.MAX_LENGTH_OF_NAME) String key, + @NonNull @Size(min = 0L, max = Event.Limit.MAX_LENGTH_OF_VALUE) + String value) { + builder.add(key, value); + return this; + } + + /** + * Adds a {@link AnalyticsDoubleProperty} to the {@link AnalyticsProperties} under + * construction. + * + * @param key A name for the property + * @param value A Double to store in the property + * @return Current Builder instance, for fluent method chaining + */ + @NonNull + public ClickstreamItem.Builder add(@NonNull @Size(min = 1L, max = Event.Limit.MAX_LENGTH_OF_NAME) String key, + @NonNull Double value) { + builder.add(key, value); + return this; + } + + /** + * Adds a {@link AnalyticsBooleanProperty} to the {@link AnalyticsProperties} under + * construction. + * + * @param key A name for the property + * @param value A Boolean to store in the property + * @return Current Builder instance, for fluent method chaining + */ + @NonNull + public ClickstreamItem.Builder add(@NonNull @Size(min = 1L, max = Event.Limit.MAX_LENGTH_OF_NAME) String key, + @NonNull Boolean value) { + builder.add(key, value); + return this; + } + + /** + * Adds an {@link AnalyticsIntegerProperty} to the {@link ClickstreamItem} under + * construction. + * + * @param key A name for the property + * @param value An Integer to store in the property + * @return Current Builder instance, for fluent method chaining + */ + @NonNull + public ClickstreamItem.Builder add(@NonNull @Size(min = 1L, max = Event.Limit.MAX_LENGTH_OF_NAME) String key, + @NonNull Integer value) { + builder.add(key, value); + return this; + } + + /** + * Adds an {@link AnalyticsLongProperty} to the {@link ClickstreamItem} under + * construction. + * + * @param key A name for the property + * @param value An Long to store in the property + * @return Current Builder instance, for fluent method chaining + */ + @NonNull + public ClickstreamItem.Builder add(@NonNull @Size(min = 1L, max = Event.Limit.MAX_LENGTH_OF_NAME) String key, + @NonNull Long value) { + builder.add(key, AnalyticsLongProperty.from(value)); + return this; + } + + /** + * Builds an instance of {@link ClickstreamItem}, using the provided values. + * + * @return An {@link ClickstreamItem} + */ + @NonNull + public ClickstreamItem build() { + return new ClickstreamItem(this); + } + } +} diff --git a/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsClient.java b/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsClient.java index 7bad881..40a68f8 100644 --- a/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsClient.java +++ b/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsClient.java @@ -65,7 +65,7 @@ public AnalyticsClient(@NonNull final ClickstreamContext context) { */ public void addGlobalAttribute(String name, Object value) { if (value != null) { - Event.EventError error = Event.checkAttribute(globalAttributes.size(), name, value); + Event.EventError error = EventChecker.checkAttribute(globalAttributes.size(), name, value); if (error != null) { if (!globalAttributes.containsKey(error.getErrorType())) { globalAttributes.put(error.getErrorType(), error.getErrorMessage()); @@ -99,7 +99,7 @@ public void deleteGlobalAttribute(String name) { */ public void addUserAttribute(String name, Object value) { if (value != null) { - Event.EventError error = Event.checkUserAttribute(userAttributes.length(), name, value); + Event.EventError error = EventChecker.checkUserAttribute(userAttributes.length(), name, value); if (error != null) { if (!globalAttributes.containsKey(error.getErrorType())) { globalAttributes.put(error.getErrorType(), error.getErrorMessage()); diff --git a/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsEvent.java b/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsEvent.java index 6febd28..fe379c0 100644 --- a/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsEvent.java +++ b/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsEvent.java @@ -19,8 +19,10 @@ import com.amazonaws.logging.Log; import com.amazonaws.logging.LogFactory; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import software.aws.solution.clickstream.ClickstreamItem; import software.aws.solution.clickstream.client.system.AndroidAppDetails; import software.aws.solution.clickstream.client.system.AndroidConnectivity; import software.aws.solution.clickstream.client.system.AndroidDeviceDetails; @@ -45,6 +47,7 @@ public class AnalyticsEvent implements JSONSerializable { private String sdkName; private String sdkVersion; private final JSONObject attributes = new JSONObject(); + private final JSONArray items = new JSONArray(); private final JSONObject userAttributes; private final Long timestamp; private final String uniqueId; @@ -249,7 +252,7 @@ public void addAttribute(final String name, final Object value) { return; } if (null != value) { - Event.EventError attributeError = Event.checkAttribute(getCurrentNumOfAttributes(), name, value); + Event.EventError attributeError = EventChecker.checkAttribute(getCurrentNumOfAttributes(), name, value); try { if (attributeError != null) { if (!attributes.has(attributeError.getErrorType())) { @@ -266,6 +269,32 @@ public void addAttribute(final String name, final Object value) { } } + /** + * Adds items to this {@link AnalyticsEvent}. + * + * @param items The name of the attribute. + */ + public void addItems(final ClickstreamItem[] items) { + if (null == items) { + return; + } + try { + for (ClickstreamItem item : items) { +// Event.EventError attributeError = EventChecker.checkAttribute(getCurrentNumOfAttributes(), name, value); +// +// if (attributeError != null) { +// if (!attributes.has(attributeError.getErrorType())) { +// attributes.putOpt(attributeError.getErrorType(), attributeError.getErrorMessage()); +// } +// } else { +// attributes.putOpt(name, value); +// } + } + } catch (JSONException exception) { + LOG.error("error parsing json, error message:" + exception.getMessage()); + } + } + /** * add internal attribute for not check attribute error, for example not check attribute value length * can allow exception stack completely record. diff --git a/clickstream/src/main/java/software/aws/solution/clickstream/client/Event.java b/clickstream/src/main/java/software/aws/solution/clickstream/client/Event.java index 7b82e4c..cea58f5 100644 --- a/clickstream/src/main/java/software/aws/solution/clickstream/client/Event.java +++ b/clickstream/src/main/java/software/aws/solution/clickstream/client/Event.java @@ -15,114 +15,16 @@ package software.aws.solution.clickstream.client; -import com.amazonaws.logging.Log; -import com.amazonaws.logging.LogFactory; -import software.aws.solution.clickstream.client.util.StringUtil; - import java.util.regex.Pattern; /** * handle the event errors. */ public final class Event { - private static final Log LOG = LogFactory.getLog(EventError.class); private Event() { } - /** - * check the attribute error. - * - * @param currentNumber current attribute number - * @param name attribute name. - * @param value attribute value. - * @return the ErrorType - */ - public static EventError checkAttribute(int currentNumber, String name, Object value) { - if (currentNumber >= Limit.MAX_NUM_OF_ATTRIBUTES) { - LOG.error("reached the max number of attributes limit (" - + Limit.MAX_NUM_OF_ATTRIBUTES + "). and the attribute: " + name + " will not be recorded"); - return new EventError(ErrorType.ATTRIBUTE_SIZE_EXCEED, - StringUtil.clipString("attribute name: " + name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); - } - if (name.length() > Limit.MAX_LENGTH_OF_NAME) { - LOG.error("attribute : " + name + ", reached the max length of attributes name limit(" - + Limit.MAX_LENGTH_OF_NAME + "). current length is:(" + name.length() + - ") and the attribute will not be recorded"); - return new EventError(ErrorType.ATTRIBUTE_NAME_LENGTH_EXCEED, - StringUtil.clipString("attribute name length is:(" + name.length() + ") name is:" + name, - Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); - } - if (!isValidName(name)) { - LOG.error("attribute : " + name + ", was not valid, attribute name can only contains" + - " uppercase and lowercase letters, underscores, number, and is not start with a number." + - " so the attribute will not be recorded"); - return new EventError(ErrorType.ATTRIBUTE_NAME_INVALID, - StringUtil.clipString(name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); - } - - if (value instanceof String) { - int valueLength = ((String) value).length(); - if (valueLength > Limit.MAX_LENGTH_OF_VALUE) { - LOG.error("attribute : " + name + ", reached the max length of attributes value limit (" - + Limit.MAX_LENGTH_OF_VALUE + "). current length is:(" + valueLength + - "). and the attribute will not be recorded, attribute value:" + value); - - return new EventError(ErrorType.ATTRIBUTE_VALUE_LENGTH_EXCEED, - StringUtil.clipString("attribute name:" + name + ", attribute value:" + value, - Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); - } - } - return null; - } - - /** - * check the user attribute error. - * - * @param currentNumber current user attribute number. - * @param name attribute name. - * @param value attribute value. - * @return the ErrorType - */ - public static EventError checkUserAttribute(int currentNumber, String name, Object value) { - if (currentNumber >= Limit.MAX_NUM_OF_USER_ATTRIBUTES) { - LOG.error("reached the max number of user attributes limit (" - + Limit.MAX_NUM_OF_USER_ATTRIBUTES + "). and the user attribute: " + name + " will not be recorded"); - return new EventError(ErrorType.ATTRIBUTE_SIZE_EXCEED, - StringUtil.clipString("attribute name: " + name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); - } - if (name.length() > Limit.MAX_LENGTH_OF_NAME) { - LOG.error("user attribute : " + name + ", reached the max length of attributes name limit(" - + Limit.MAX_LENGTH_OF_NAME + "). current length is:(" + name.length() + - ") and the attribute will not be recorded"); - return new EventError(ErrorType.ATTRIBUTE_NAME_LENGTH_EXCEED, - StringUtil.clipString("user attribute name length is:(" + name.length() + ") name is:" + name, - Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); - } - if (!isValidName(name)) { - LOG.error("user attribute : " + name + ", reached the max length of attributes name limit(" - + Limit.MAX_LENGTH_OF_NAME + "). current length is:(" + name.length() + - ") and the attribute will not be recorded"); - LOG.error("user attribute : " + name + ", was not valid, user attribute name can only contains" + - " uppercase and lowercase letters, underscores, number, and is not start with a number." + - " so the attribute will not be recorded"); - return new EventError(ErrorType.ATTRIBUTE_NAME_INVALID, - StringUtil.clipString(name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); - } - if (value instanceof String) { - int valueLength = ((String) value).length(); - if (valueLength > Limit.MAX_LENGTH_OF_USER_VALUE) { - LOG.error("user attribute : " + name + ", reached the max length of attributes value limit (" - + Limit.MAX_LENGTH_OF_USER_VALUE + "). current length is:(" + valueLength + - "). and the attribute will not be recorded, attribute value:" + value); - return new EventError(ErrorType.ATTRIBUTE_VALUE_LENGTH_EXCEED, - StringUtil.clipString("user attribute name:" + name + ", attribute value:" + value, - Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); - } - } - return null; - } - /** * verify the string whether only contains number, uppercase and lowercase letters, underscores, * and is not start with a number. @@ -166,7 +68,7 @@ public static final class Limit { /** * max limit of error attribute value length. */ - private static final int MAX_LENGTH_OF_ERROR_VALUE = 256; + public static final int MAX_LENGTH_OF_ERROR_VALUE = 256; private Limit() { } @@ -176,15 +78,36 @@ private Limit() { * event error type. */ public static final class ErrorType { - private static final String ATTRIBUTE_NAME_INVALID = "_error_name_invalid"; - private static final String ATTRIBUTE_NAME_LENGTH_EXCEED = "_error_name_length_exceed"; - private static final String ATTRIBUTE_VALUE_LENGTH_EXCEED = "_error_value_length_exceed"; - private static final String ATTRIBUTE_SIZE_EXCEED = "_error_attribute_size_exceed"; + static final String ATTRIBUTE_NAME_INVALID = "_error_name_invalid"; + static final String ATTRIBUTE_NAME_LENGTH_EXCEED = "_error_name_length_exceed"; + static final String ATTRIBUTE_VALUE_LENGTH_EXCEED = "_error_value_length_exceed"; + static final String ATTRIBUTE_SIZE_EXCEED = "_error_attribute_size_exceed"; private ErrorType() { } } + + public static final class ErrorCode { + static final int NO_ERROR = 0; + static final int EVENT_NAME_INVALID = 1001; + static final int EVENT_NAME_LENGTH_EXCEED = 1002; + static final int ATTRIBUTE_NAME_LENGTH_EXCEED = 2001; + static final int ATTRIBUTE_NAME_INVALID = 2002; + static final int ATTRIBUTE_VALUE_LENGTH_EXCEED = 2003; + static final int ATTRIBUTE_SIZE_EXCEED = 2004; + static final int USER_ATTRIBUTE_SIZE_EXCEED = 3001; + static final int USER_ATTRIBUTE_NAME_LENGTH_EXCEED = 3002; + static final int USER_ATTRIBUTE_NAME_INVALID = 3003; + static final int USER_ATTRIBUTE_VALUE_LENGTH_EXCEED = 3004; + static final int ITEM_SIZE_EXCEED = 4001; + static final int ITEM_VALUE_LENGTH_EXCEED = 4002; + static final int ITEM_ATTRIBUTE_SIZE_EXCEED = 4003; + + private ErrorCode() { + } + } + /** * Event for return. */ diff --git a/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java b/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java new file mode 100644 index 0000000..8fbc807 --- /dev/null +++ b/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java @@ -0,0 +1,127 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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. + */ + +package software.aws.solution.clickstream.client; + +import com.amazonaws.logging.Log; +import com.amazonaws.logging.LogFactory; +import software.aws.solution.clickstream.client.Event.ErrorType; +import software.aws.solution.clickstream.client.Event.EventError; +import software.aws.solution.clickstream.client.Event.Limit; +import software.aws.solution.clickstream.client.util.StringUtil; + +/** + * handle the event errors. + */ +public final class EventChecker { + private static final Log LOG = LogFactory.getLog(EventChecker.class); + + private EventChecker() { + } + + /** + * check the attribute error. + * + * @param currentNumber current attribute number + * @param name attribute name. + * @param value attribute value. + * @return the ErrorType + */ + public static EventError checkAttribute(int currentNumber, String name, Object value) { + if (currentNumber >= Limit.MAX_NUM_OF_ATTRIBUTES) { + LOG.error("reached the max number of attributes limit (" + + Limit.MAX_NUM_OF_ATTRIBUTES + "). and the attribute: " + name + " will not be recorded"); + return new EventError(ErrorType.ATTRIBUTE_SIZE_EXCEED, + StringUtil.clipString("attribute name: " + name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); + } + if (name.length() > Limit.MAX_LENGTH_OF_NAME) { + LOG.error("attribute : " + name + ", reached the max length of attributes name limit(" + + Limit.MAX_LENGTH_OF_NAME + "). current length is:(" + name.length() + + ") and the attribute will not be recorded"); + return new EventError(ErrorType.ATTRIBUTE_NAME_LENGTH_EXCEED, + StringUtil.clipString("attribute name length is:(" + name.length() + ") name is:" + name, + Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); + } + if (!Event.isValidName(name)) { + LOG.error("attribute : " + name + ", was not valid, attribute name can only contains" + + " uppercase and lowercase letters, underscores, number, and is not start with a number." + + " so the attribute will not be recorded"); + return new EventError(ErrorType.ATTRIBUTE_NAME_INVALID, + StringUtil.clipString(name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); + } + + if (value instanceof String) { + int valueLength = ((String) value).length(); + if (valueLength > Limit.MAX_LENGTH_OF_VALUE) { + LOG.error("attribute : " + name + ", reached the max length of attributes value limit (" + + Limit.MAX_LENGTH_OF_VALUE + "). current length is:(" + valueLength + + "). and the attribute will not be recorded, attribute value:" + value); + + return new EventError(ErrorType.ATTRIBUTE_VALUE_LENGTH_EXCEED, + StringUtil.clipString("attribute name:" + name + ", attribute value:" + value, + Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); + } + } + return null; + } + + /** + * check the user attribute error. + * + * @param currentNumber current user attribute number. + * @param name attribute name. + * @param value attribute value. + * @return the ErrorType + */ + public static EventError checkUserAttribute(int currentNumber, String name, Object value) { + if (currentNumber >= Limit.MAX_NUM_OF_USER_ATTRIBUTES) { + LOG.error("reached the max number of user attributes limit (" + + Limit.MAX_NUM_OF_USER_ATTRIBUTES + "). and the user attribute: " + name + " will not be recorded"); + return new EventError(ErrorType.ATTRIBUTE_SIZE_EXCEED, + StringUtil.clipString("attribute name: " + name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); + } + if (name.length() > Limit.MAX_LENGTH_OF_NAME) { + LOG.error("user attribute : " + name + ", reached the max length of attributes name limit(" + + Limit.MAX_LENGTH_OF_NAME + "). current length is:(" + name.length() + + ") and the attribute will not be recorded"); + return new EventError(ErrorType.ATTRIBUTE_NAME_LENGTH_EXCEED, + StringUtil.clipString("user attribute name length is:(" + name.length() + ") name is:" + name, + Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); + } + if (!Event.isValidName(name)) { + LOG.error("user attribute : " + name + ", reached the max length of attributes name limit(" + + Limit.MAX_LENGTH_OF_NAME + "). current length is:(" + name.length() + + ") and the attribute will not be recorded"); + LOG.error("user attribute : " + name + ", was not valid, user attribute name can only contains" + + " uppercase and lowercase letters, underscores, number, and is not start with a number." + + " so the attribute will not be recorded"); + return new EventError(ErrorType.ATTRIBUTE_NAME_INVALID, + StringUtil.clipString(name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); + } + if (value instanceof String) { + int valueLength = ((String) value).length(); + if (valueLength > Limit.MAX_LENGTH_OF_USER_VALUE) { + LOG.error("user attribute : " + name + ", reached the max length of attributes value limit (" + + Limit.MAX_LENGTH_OF_USER_VALUE + "). current length is:(" + valueLength + + "). and the attribute will not be recorded, attribute value:" + value); + return new EventError(ErrorType.ATTRIBUTE_VALUE_LENGTH_EXCEED, + StringUtil.clipString("user attribute name:" + name + ", attribute value:" + value, + Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); + } + } + return null; + } + +} diff --git a/clickstream/src/test/java/software/aws/solution/clickstream/IntegrationTest.java b/clickstream/src/test/java/software/aws/solution/clickstream/IntegrationTest.java index 1820641..633376c 100644 --- a/clickstream/src/test/java/software/aws/solution/clickstream/IntegrationTest.java +++ b/clickstream/src/test/java/software/aws/solution/clickstream/IntegrationTest.java @@ -257,6 +257,41 @@ public void testDeleteGlobalAttribute() throws Exception { cursor.close(); } + /** + * test add items. + * + * @throws Exception exception + */ + @Test + public void testAddItem() throws Exception { + ClickstreamItem item = ClickstreamItem.builder() + .add("a", 1) + .build(); + + ClickstreamEvent event = ClickstreamEvent.builder() + .name("PasswordReset") + .add("Message", "SMS") + .add("Successful", true) + .add("ProcessDuration", 792) + .add("Number", 20.1) + .setItems(new ClickstreamItem[] {item}) + .build(); + ClickstreamAnalytics.recordEvent(event); + assertEquals(1, dbUtil.getTotalNumber()); + Cursor cursor = dbUtil.queryAllEvents(); + cursor.moveToFirst(); + String eventString = cursor.getString(2); + JSONObject jsonObject = new JSONObject(eventString); + JSONObject attribute = jsonObject.getJSONObject("attributes"); + + Assert.assertEquals("HUAWEI", attribute.getString("channel")); + + ClickstreamAnalytics.flushEvents(); + Thread.sleep(1000); + assertEquals(0, dbUtil.getTotalNumber()); + cursor.close(); + } + /** * test add user attribute. * From 82f3f233d73f5a8e13564658f094744b02fe89f3 Mon Sep 17 00:00:00 2001 From: xiaoweii Date: Fri, 13 Oct 2023 15:34:50 +0800 Subject: [PATCH 2/8] feat: discard invalid item. --- .../clickstream/client/AnalyticsEvent.java | 2 +- .../clickstream/client/EventChecker.java | 14 +---- .../clickstream/AnalyticsEventTest.java | 60 +++---------------- 3 files changed, 10 insertions(+), 66 deletions(-) diff --git a/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsEvent.java b/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsEvent.java index 927cecb..d29394b 100644 --- a/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsEvent.java +++ b/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsEvent.java @@ -291,7 +291,7 @@ public void addItems(final ClickstreamItem[] items) { attributes.putOpt(Event.ReservedAttribute.ERROR_CODE, attributeError.getErrorCode()); attributes.putOpt(Event.ReservedAttribute.ERROR_MESSAGE, attributeError.getErrorMessage()); } - if (attributeError.getErrorCode() != Event.ErrorCode.ITEM_SIZE_EXCEED) { + if (attributeError.getErrorCode() == 0) { eventItems.put(item.getAttributes()); } } diff --git a/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java b/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java index 5e8f7ba..b776027 100644 --- a/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java +++ b/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java @@ -183,10 +183,7 @@ public static EventError checkItemAttribute(int currentNumber, ClickstreamItem i Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); } int customKeyNumber = 0; - EventError error = null; Iterator keys = item.getAttributes().keys(); - ArrayList invalidKeys = new ArrayList<>(); - while (keys.hasNext()) { String key = keys.next(); String valueStr = ""; @@ -232,17 +229,8 @@ public static EventError checkItemAttribute(int currentNumber, ClickstreamItem i Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); } if (attributeError != null) { - invalidKeys.add(key); - if (error == null) { - error = attributeError; - } - } - } - if (error != null) { - for (String key : invalidKeys) { - item.getAttributes().remove(key); + return attributeError; } - return error; } return new EventError(ErrorCode.NO_ERROR, ""); } diff --git a/clickstream/src/test/java/software/aws/solution/clickstream/AnalyticsEventTest.java b/clickstream/src/test/java/software/aws/solution/clickstream/AnalyticsEventTest.java index 25bb7b8..7b90cdf 100644 --- a/clickstream/src/test/java/software/aws/solution/clickstream/AnalyticsEventTest.java +++ b/clickstream/src/test/java/software/aws/solution/clickstream/AnalyticsEventTest.java @@ -174,11 +174,10 @@ public void testReachedTheMaxNumOfCustomItemAttribute() throws JSONException { } event.addItems(new ClickstreamItem[] {builder.build()}); JSONObject attributes = event.getAttributes(); - JSONObject eventItem = (JSONObject) event.getItems().get(0); Assert.assertEquals(Event.ErrorCode.ITEM_CUSTOM_ATTRIBUTE_SIZE_EXCEED, attributes.getInt(Event.ReservedAttribute.ERROR_CODE)); - Assert.assertEquals(12, eventItem.length()); - Assert.assertFalse(eventItem.has("custom_key_11")); + JSONArray eventItems = event.getItems(); + Assert.assertEquals(0, eventItems.length()); } /** @@ -196,11 +195,10 @@ public void testReachedTheMaxLengthOfCustomItemAttributeKey() throws JSONExcepti .build(); event.addItems(new ClickstreamItem[] {item}); JSONObject attributes = event.getAttributes(); - JSONObject eventItem = (JSONObject) event.getItems().get(0); Assert.assertEquals(Event.ErrorCode.ITEM_CUSTOM_ATTRIBUTE_KEY_LENGTH_EXCEED, attributes.getInt(Event.ReservedAttribute.ERROR_CODE)); - Assert.assertEquals(123, eventItem.getInt(ClickstreamAnalytics.Item.ITEM_ID)); - Assert.assertFalse(eventItem.has(exceedLengthName)); + JSONArray eventItems = event.getItems(); + Assert.assertEquals(0, eventItems.length()); } /** @@ -217,11 +215,10 @@ public void testAddInvalidCustomItemAttributeKey() throws JSONException { .build(); event.addItems(new ClickstreamItem[] {item}); JSONObject attributes = event.getAttributes(); - JSONObject eventItem = (JSONObject) event.getItems().get(0); Assert.assertEquals(Event.ErrorCode.ITEM_CUSTOM_ATTRIBUTE_KEY_INVALID, attributes.getInt(Event.ReservedAttribute.ERROR_CODE)); - Assert.assertEquals(123, eventItem.getInt(ClickstreamAnalytics.Item.ITEM_ID)); - Assert.assertFalse(eventItem.has("01test")); + JSONArray eventItems = event.getItems(); + Assert.assertEquals(0, eventItems.length()); } @@ -246,51 +243,10 @@ public void testReachedTheMaxLengthOfCustomItemAttributeValue() throws JSONExcep .build(); event.addItems(new ClickstreamItem[] {item}); JSONObject attributes = event.getAttributes(); - JSONObject eventItem = (JSONObject) event.getItems().get(0); - Assert.assertEquals(Event.ErrorCode.ITEM_ATTRIBUTE_VALUE_LENGTH_EXCEED, - attributes.getInt(Event.ReservedAttribute.ERROR_CODE)); - Assert.assertEquals(123, eventItem.getInt(ClickstreamAnalytics.Item.ITEM_ID)); - Assert.assertFalse(eventItem.has("testKey")); - Assert.assertFalse(eventItem.has(ClickstreamAnalytics.Item.ITEM_NAME)); - } - - - /** - * test add items with multiple errors in one item. - * - * @throws JSONException exception - */ - @Test - public void testMultiErrorInOneItem() throws JSONException { - AnalyticsEvent event = analyticsClient.createEvent("testEvent"); - String exceedLengthName = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij1"; - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 21; i++) { - sb.append(exceedLengthName); - } - String exceedLengthValue = sb.toString(); - ClickstreamItem.Builder builder = new ClickstreamItem.Builder() - .add(ClickstreamAnalytics.Item.ITEM_ID, 123) - .add(ClickstreamAnalytics.Item.ITEM_NAME, exceedLengthValue) - .add("exceedValueLengthKey", exceedLengthValue) - .add("01test", "test_value") - .add(exceedLengthName, "test_value"); - - for (int i = 0; i < 8; i++) { - builder.add("custom_key_" + (i + 1), "custom_value"); - } - - event.addItems(new ClickstreamItem[] {builder.build()}); - JSONObject attributes = event.getAttributes(); - JSONObject eventItem = (JSONObject) event.getItems().get(0); Assert.assertEquals(Event.ErrorCode.ITEM_ATTRIBUTE_VALUE_LENGTH_EXCEED, attributes.getInt(Event.ReservedAttribute.ERROR_CODE)); - Assert.assertEquals(123, eventItem.getInt(ClickstreamAnalytics.Item.ITEM_ID)); - Assert.assertFalse(eventItem.has("testKey")); - Assert.assertFalse(eventItem.has("exceedValueLengthKey")); - Assert.assertFalse(eventItem.has("01test")); - Assert.assertFalse(eventItem.has(exceedLengthName)); - Assert.assertFalse(eventItem.has("custom_key_8")); + JSONArray eventItems = event.getItems(); + Assert.assertEquals(0, eventItems.length()); } } From 2f1636917fcc8b9ffdd94d3d71cfb96de6bd912a Mon Sep 17 00:00:00 2001 From: xiaoweii Date: Fri, 13 Oct 2023 16:04:55 +0800 Subject: [PATCH 3/8] fix: delete unused import --- .../software/aws/solution/clickstream/client/EventChecker.java | 1 - 1 file changed, 1 deletion(-) diff --git a/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java b/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java index b776027..875e5d7 100644 --- a/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java +++ b/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java @@ -25,7 +25,6 @@ import software.aws.solution.clickstream.client.Event.Limit; import software.aws.solution.clickstream.client.util.StringUtil; -import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.Set; From b04241647f8762d27d729c64f84e990885266b35 Mon Sep 17 00:00:00 2001 From: xiaoweii Date: Fri, 13 Oct 2023 17:53:33 +0800 Subject: [PATCH 4/8] fix: fix build issue. --- .../solution/clickstream/IntegrationTest.java | 190 +++++++++++------- 1 file changed, 118 insertions(+), 72 deletions(-) diff --git a/clickstream/src/test/java/software/aws/solution/clickstream/IntegrationTest.java b/clickstream/src/test/java/software/aws/solution/clickstream/IntegrationTest.java index e303e95..4459559 100644 --- a/clickstream/src/test/java/software/aws/solution/clickstream/IntegrationTest.java +++ b/clickstream/src/test/java/software/aws/solution/clickstream/IntegrationTest.java @@ -232,43 +232,6 @@ public void testAddGlobalAttribute() throws Exception { } } - - /** - * test add delete global attribute. - * - * @throws Exception exception - */ - @Test - public void testDeleteGlobalAttribute() throws Exception { - ClickstreamAttribute globalAttribute = ClickstreamAttribute.builder() - .add("channel", "HUAWEI") - .add("level", 5.1) - .add("class", 6) - .add("isOpenNotification", true) - .build(); - ClickstreamAnalytics.addGlobalAttributes(globalAttribute); - ClickstreamEvent event = ClickstreamEvent.builder() - .name("PasswordReset") - .add("Message", "SMS") - .add("Successful", true) - .add("ProcessDuration", 792) - .add("Number", 20.1) - .build(); - ClickstreamAnalytics.deleteGlobalAttributes("level"); - ClickstreamAnalytics.recordEvent(event); - assertEquals(1, dbUtil.getTotalNumber()); - try (Cursor cursor = dbUtil.queryAllEvents()) { - cursor.moveToFirst(); - String eventString = cursor.getString(2); - JSONObject jsonObject = new JSONObject(eventString); - JSONObject attribute = jsonObject.getJSONObject("attributes"); - - Assert.assertEquals("HUAWEI", attribute.getString("channel")); - Assert.assertFalse(attribute.has("level")); - Assert.assertTrue(attribute.getBoolean("isOpenNotification")); - } - } - /** * test add items. * @@ -321,6 +284,47 @@ public void testAddItem() throws Exception { } } + + /** + * test add delete global attribute. + * + * @throws Exception exception + */ + @Test + public void testDeleteGlobalAttribute() throws Exception { + ClickstreamAttribute globalAttribute = ClickstreamAttribute.builder() + .add("channel", "HUAWEI") + .add("level", 5.1) + .add("class", 6) + .add("isOpenNotification", true) + .build(); + ClickstreamAnalytics.addGlobalAttributes(globalAttribute); + ClickstreamEvent event = ClickstreamEvent.builder() + .name("PasswordReset") + .add("Message", "SMS") + .add("Successful", true) + .add("ProcessDuration", 792) + .add("Number", 20.1) + .build(); + ClickstreamAnalytics.deleteGlobalAttributes("level"); + ClickstreamAnalytics.recordEvent(event); + assertEquals(1, dbUtil.getTotalNumber()); + Cursor cursor = dbUtil.queryAllEvents(); + cursor.moveToFirst(); + String eventString = cursor.getString(2); + JSONObject jsonObject = new JSONObject(eventString); + JSONObject attribute = jsonObject.getJSONObject("attributes"); + + Assert.assertEquals("HUAWEI", attribute.getString("channel")); + Assert.assertFalse(attribute.has("level")); + Assert.assertTrue(attribute.getBoolean("isOpenNotification")); + + ClickstreamAnalytics.flushEvents(); + Thread.sleep(1000); + assertEquals(0, dbUtil.getTotalNumber()); + cursor.close(); + } + /** * test add user attribute. * @@ -348,22 +352,26 @@ public void testAddUserAttributes() throws Exception { ClickstreamAnalytics.recordEvent(event); assertEquals(3, dbUtil.getTotalNumber()); - try (Cursor cursor = dbUtil.queryAllEvents()) { - cursor.moveToLast(); - String eventString = cursor.getString(2); - JSONObject jsonObject = new JSONObject(eventString); - JSONObject attribute = jsonObject.getJSONObject("attributes"); - JSONObject user = jsonObject.getJSONObject("user"); - Assert.assertEquals("13212", ((JSONObject) user.get(Event.ReservedAttribute.USER_ID)).getString("value")); - Assert.assertEquals(21, ((JSONObject) user.get("_user_age")).getInt("value")); - Assert.assertTrue(((JSONObject) user.get("_user_age")).has("set_timestamp")); - Assert.assertEquals("carl", ((JSONObject) user.get("_user_name")).getString("value")); - Assert.assertTrue(((JSONObject) user.get("_user_name")).has("set_timestamp")); - Assert.assertEquals(timestamp, ((JSONObject) user.get("timestamp")).getLong("value")); + Cursor cursor = dbUtil.queryAllEvents(); + cursor.moveToLast(); + String eventString = cursor.getString(2); + JSONObject jsonObject = new JSONObject(eventString); + JSONObject attribute = jsonObject.getJSONObject("attributes"); + JSONObject user = jsonObject.getJSONObject("user"); + Assert.assertEquals("13212", ((JSONObject) user.get(Event.ReservedAttribute.USER_ID)).getString("value")); + Assert.assertEquals(21, ((JSONObject) user.get("_user_age")).getInt("value")); + Assert.assertTrue(((JSONObject) user.get("_user_age")).has("set_timestamp")); + Assert.assertEquals("carl", ((JSONObject) user.get("_user_name")).getString("value")); + Assert.assertTrue(((JSONObject) user.get("_user_name")).has("set_timestamp")); + Assert.assertEquals(timestamp, ((JSONObject) user.get("timestamp")).getLong("value")); + + Assert.assertTrue(attribute.getBoolean("Successful")); + Assert.assertEquals("SMS", attribute.getString("Message")); - Assert.assertTrue(attribute.getBoolean("Successful")); - Assert.assertEquals("SMS", attribute.getString("Message")); - } + ClickstreamAnalytics.flushEvents(); + Thread.sleep(1000); + assertEquals(0, dbUtil.getTotalNumber()); + cursor.close(); } /** @@ -391,15 +399,20 @@ public void testModifyUserId() throws Exception { ClickstreamAnalytics.setUserId("12345"); ClickstreamAnalytics.recordEvent(event); assertEquals(4, dbUtil.getTotalNumber()); - try (Cursor cursor = dbUtil.queryAllEvents()) { - cursor.moveToLast(); - String eventString = cursor.getString(2); - JSONObject jsonObject = new JSONObject(eventString); - JSONObject user = jsonObject.getJSONObject("user"); - Assert.assertEquals("12345", ((JSONObject) user.get(Event.ReservedAttribute.USER_ID)).getString("value")); - Assert.assertFalse(user.has("_user_age")); - Assert.assertFalse(user.has("_user_name")); - } + + Cursor cursor = dbUtil.queryAllEvents(); + cursor.moveToLast(); + String eventString = cursor.getString(2); + JSONObject jsonObject = new JSONObject(eventString); + JSONObject user = jsonObject.getJSONObject("user"); + Assert.assertEquals("12345", ((JSONObject) user.get(Event.ReservedAttribute.USER_ID)).getString("value")); + Assert.assertFalse(user.has("_user_age")); + Assert.assertFalse(user.has("_user_name")); + + ClickstreamAnalytics.flushEvents(); + Thread.sleep(1000); + assertEquals(0, dbUtil.getTotalNumber()); + cursor.close(); } /** @@ -428,15 +441,19 @@ public void testSetUserIdNull() throws Exception { ClickstreamAnalytics.recordEvent(event); assertEquals(4, dbUtil.getTotalNumber()); - try (Cursor cursor = dbUtil.queryAllEvents()) { - cursor.moveToLast(); - String eventString = cursor.getString(2); - JSONObject jsonObject = new JSONObject(eventString); - JSONObject user = jsonObject.getJSONObject("user"); - Assert.assertFalse(user.has(Event.ReservedAttribute.USER_ID)); - Assert.assertEquals(21, ((JSONObject) user.get("_user_age")).get("value")); - Assert.assertEquals("carl", ((JSONObject) user.get("_user_name")).get("value")); - } + Cursor cursor = dbUtil.queryAllEvents(); + cursor.moveToLast(); + String eventString = cursor.getString(2); + JSONObject jsonObject = new JSONObject(eventString); + JSONObject user = jsonObject.getJSONObject("user"); + Assert.assertFalse(user.has(Event.ReservedAttribute.USER_ID)); + Assert.assertEquals(21, ((JSONObject) user.get("_user_age")).get("value")); + Assert.assertEquals("carl", ((JSONObject) user.get("_user_name")).get("value")); + + ClickstreamAnalytics.flushEvents(); + Thread.sleep(1000); + assertEquals(0, dbUtil.getTotalNumber()); + cursor.close(); } /** @@ -501,6 +518,8 @@ public void testRecordEventWithSubmitterTwice() throws Exception { ClickstreamAnalytics.recordEvent(event); } assertEquals(20, dbUtil.getTotalNumber()); + Thread.sleep(1000); + assertEquals(0, dbUtil.getTotalNumber()); } /** @@ -537,6 +556,10 @@ public void testCustomConfig() throws Exception { String appId = jsonObject.getString("app_id"); assertEquals("23982", appId); } + + ClickstreamAnalytics.flushEvents(); + Thread.sleep(1500); + assertEquals(0, dbUtil.getTotalNumber()); } /** @@ -577,8 +600,15 @@ public void testCustomDnsFail() throws Exception { assertEquals(1, dbUtil.getTotalNumber()); setHttpRequestTimeOut(1L); ClickstreamAnalytics.flushEvents(); - Thread.sleep(1000); + Thread.sleep(2000); assertEquals(1, dbUtil.getTotalNumber()); + + dns.setDefaultIp("127.0.0.1"); + setHttpRequestTimeOut(15L); + ClickstreamAnalytics.flushEvents(); + // wait for success + Thread.sleep(1500); + assertEquals(0, dbUtil.getTotalNumber()); } /** @@ -599,8 +629,14 @@ public void testCustomDnsResolutionTimeoutFail() throws Exception { ClickstreamAnalytics.recordEvent("testRecordEvent"); assertEquals(1, dbUtil.getTotalNumber()); ClickstreamAnalytics.flushEvents(); - Thread.sleep(1000); + Thread.sleep(1500); assertEquals(1, dbUtil.getTotalNumber()); + + dns.setIsResolutionTimeout(false); + setHttpRequestTimeOut(15L); + ClickstreamAnalytics.flushEvents(); + Thread.sleep(1000); + assertEquals(0, dbUtil.getTotalNumber()); } /** @@ -622,6 +658,11 @@ public void testCustomDnsForUnKnowHostFail() throws Exception { ClickstreamAnalytics.flushEvents(); Thread.sleep(1000); assertEquals(1, dbUtil.getTotalNumber()); + + dns.setIsUnKnowHost(false); + ClickstreamAnalytics.flushEvents(); + Thread.sleep(1000); + assertEquals(0, dbUtil.getTotalNumber()); } /** @@ -664,6 +705,11 @@ public void testSetAuthCookieFail() throws Exception { ClickstreamAnalytics.flushEvents(); Thread.sleep(1000); assertEquals(1, dbUtil.getTotalNumber()); + + ClickstreamAnalytics.getClickStreamConfiguration().withAuthCookie("testCookie"); + ClickstreamAnalytics.flushEvents(); + Thread.sleep(1000); + assertEquals(0, dbUtil.getTotalNumber()); } /** From f12736c84430ff2cf1b324c32406e690786d7c7d Mon Sep 17 00:00:00 2001 From: xiaoweii Date: Fri, 13 Oct 2023 21:04:21 +0800 Subject: [PATCH 5/8] fix: integration test case failure due to stackoverflow --- .../clickstream/AWSClickstreamPlugin.java | 10 +- .../solution/clickstream/IntegrationTest.java | 121 ++++++++++-------- 2 files changed, 72 insertions(+), 59 deletions(-) diff --git a/clickstream/src/main/java/software/aws/solution/clickstream/AWSClickstreamPlugin.java b/clickstream/src/main/java/software/aws/solution/clickstream/AWSClickstreamPlugin.java index 35aebec..8328dd2 100644 --- a/clickstream/src/main/java/software/aws/solution/clickstream/AWSClickstreamPlugin.java +++ b/clickstream/src/main/java/software/aws/solution/clickstream/AWSClickstreamPlugin.java @@ -113,10 +113,12 @@ public void recordEvent(@NonNull AnalyticsEventBehavior analyticsEvent) { final AnalyticsEvent clickstreamEvent = analyticsClient.createEvent(event.getName()); - if (clickstreamEvent != null && analyticsEvent.getProperties() != null) { - for (Map.Entry> entry : analyticsEvent.getProperties()) { - AnalyticsPropertyBehavior property = entry.getValue(); - clickstreamEvent.addAttribute(entry.getKey(), property.getValue()); + if (clickstreamEvent != null) { + if (analyticsEvent.getProperties() != null) { + for (Map.Entry> entry : analyticsEvent.getProperties()) { + AnalyticsPropertyBehavior property = entry.getValue(); + clickstreamEvent.addAttribute(entry.getKey(), property.getValue()); + } } clickstreamEvent.addItems(event.getItems()); analyticsClient.recordEvent(clickstreamEvent); diff --git a/clickstream/src/test/java/software/aws/solution/clickstream/IntegrationTest.java b/clickstream/src/test/java/software/aws/solution/clickstream/IntegrationTest.java index 4459559..a04dd6b 100644 --- a/clickstream/src/test/java/software/aws/solution/clickstream/IntegrationTest.java +++ b/clickstream/src/test/java/software/aws/solution/clickstream/IntegrationTest.java @@ -133,6 +133,8 @@ public void testRecordEventWithName() throws Exception { executeBackground(); ClickstreamAnalytics.recordEvent("testRecordEventWithName"); assertEquals(1, dbUtil.getTotalNumber()); + Thread.sleep(2500); + assertEquals(0, dbUtil.getTotalNumber()); } /** @@ -151,6 +153,8 @@ public void testRecordEventWithInvalidName() throws Exception { assertEquals(Event.PresetEvent.CLICKSTREAM_ERROR, jsonObject.getString("event_type")); } assertEquals(1, dbUtil.getTotalNumber()); + Thread.sleep(1500); + assertEquals(0, dbUtil.getTotalNumber()); } /** @@ -174,62 +178,21 @@ public void testRecordOneEvent() throws Exception { ClickstreamAnalytics.recordEvent(event); assertEquals(1, dbUtil.getTotalNumber()); - try (Cursor cursor = dbUtil.queryAllEvents()) { - cursor.moveToFirst(); - String eventString = cursor.getString(2); - JSONObject jsonObject = new JSONObject(eventString); - JSONObject attribute = jsonObject.getJSONObject("attributes"); - Assert.assertEquals("PasswordReset", jsonObject.getString("event_type")); - Assert.assertEquals("SMS", attribute.getString("Channel")); - Assert.assertTrue(attribute.getBoolean("Successful")); - Assert.assertEquals(792, attribute.getInt("ProcessDuration")); - Assert.assertEquals(120.3, attribute.getDouble("UserAge"), 0.01); - Assert.assertEquals(169823889238L, attribute.getLong("Timestamp")); - } - } - - /** - * test add global attribute. - * - * @throws Exception exception - */ - @Test - public void testAddGlobalAttribute() throws Exception { - long timestamp = System.currentTimeMillis(); - ClickstreamAttribute globalAttribute = ClickstreamAttribute.builder() - .add("channel", "HUAWEI") - .add("level", 5.1) - .add("class", 6) - .add("timestamp", timestamp) - .add("isOpenNotification", true) - .build(); - ClickstreamAnalytics.addGlobalAttributes(globalAttribute); - ClickstreamEvent event = ClickstreamEvent.builder() - .name("PasswordReset") - .add("Message", "SMS") - .add("Successful", true) - .add("ProcessDuration", 792) - .add("UserAge", 120.3) - .build(); - ClickstreamAnalytics.recordEvent(event); - assertEquals(1, dbUtil.getTotalNumber()); - try (Cursor cursor = dbUtil.queryAllEvents()) { - cursor.moveToFirst(); - String eventString = cursor.getString(2); - JSONObject jsonObject = new JSONObject(eventString); - JSONObject attribute = jsonObject.getJSONObject("attributes"); - - Assert.assertEquals("HUAWEI", attribute.getString("channel")); - Assert.assertEquals(5.1, attribute.getDouble("level"), 0.01); - Assert.assertEquals(6, attribute.getInt("class")); - Assert.assertTrue(attribute.getBoolean("isOpenNotification")); - Assert.assertEquals(timestamp, attribute.getLong("timestamp")); + Cursor cursor = dbUtil.queryAllEvents(); + cursor.moveToFirst(); + String eventString = cursor.getString(2); + JSONObject jsonObject = new JSONObject(eventString); + JSONObject attribute = jsonObject.getJSONObject("attributes"); + Assert.assertEquals("PasswordReset", jsonObject.getString("event_type")); + Assert.assertEquals("SMS", attribute.getString("Channel")); + Assert.assertTrue(attribute.getBoolean("Successful")); + Assert.assertEquals(792, attribute.getInt("ProcessDuration")); + Assert.assertEquals(120.3, attribute.getDouble("UserAge"), 0.01); + Assert.assertEquals(169823889238L, attribute.getLong("Timestamp")); - Assert.assertEquals("SMS", attribute.getString("Message")); - Assert.assertTrue(attribute.getBoolean("Successful")); - Assert.assertEquals(792, attribute.getInt("ProcessDuration")); - Assert.assertEquals(120.3, attribute.getDouble("UserAge"), 0.01); - } + Thread.sleep(2500); + assertEquals(0, dbUtil.getTotalNumber()); + cursor.close(); } /** @@ -284,6 +247,54 @@ public void testAddItem() throws Exception { } } + /** + * test add global attribute. + * + * @throws Exception exception + */ + @Test + public void testAddGlobalAttribute() throws Exception { + long timestamp = System.currentTimeMillis(); + ClickstreamAttribute globalAttribute = ClickstreamAttribute.builder() + .add("channel", "HUAWEI") + .add("level", 5.1) + .add("class", 6) + .add("timestamp", timestamp) + .add("isOpenNotification", true) + .build(); + ClickstreamAnalytics.addGlobalAttributes(globalAttribute); + ClickstreamEvent event = ClickstreamEvent.builder() + .name("PasswordReset") + .add("Message", "SMS") + .add("Successful", true) + .add("ProcessDuration", 792) + .add("UserAge", 120.3) + .build(); + ClickstreamAnalytics.recordEvent(event); + assertEquals(1, dbUtil.getTotalNumber()); + Cursor cursor = dbUtil.queryAllEvents(); + cursor.moveToFirst(); + String eventString = cursor.getString(2); + JSONObject jsonObject = new JSONObject(eventString); + JSONObject attribute = jsonObject.getJSONObject("attributes"); + + Assert.assertEquals("HUAWEI", attribute.getString("channel")); + Assert.assertEquals(5.1, attribute.getDouble("level"), 0.01); + Assert.assertEquals(6, attribute.getInt("class")); + Assert.assertTrue(attribute.getBoolean("isOpenNotification")); + Assert.assertEquals(timestamp, attribute.getLong("timestamp")); + + Assert.assertEquals("SMS", attribute.getString("Message")); + Assert.assertTrue(attribute.getBoolean("Successful")); + Assert.assertEquals(792, attribute.getInt("ProcessDuration")); + Assert.assertEquals(120.3, attribute.getDouble("UserAge"), 0.01); + + ClickstreamAnalytics.flushEvents(); + Thread.sleep(1000); + assertEquals(0, dbUtil.getTotalNumber()); + cursor.close(); + } + /** * test add delete global attribute. From cc85ab0a6931d404408939201381dcbd82d68f7a Mon Sep 17 00:00:00 2001 From: xiaoweii Date: Fri, 8 Dec 2023 13:17:53 +0800 Subject: [PATCH 6/8] fix: change log level in EventChecker --- .../solution/clickstream/client/Event.java | 24 ++- .../clickstream/client/EventChecker.java | 161 ++++++++++-------- 2 files changed, 110 insertions(+), 75 deletions(-) diff --git a/clickstream/src/main/java/software/aws/solution/clickstream/client/Event.java b/clickstream/src/main/java/software/aws/solution/clickstream/client/Event.java index 715bea0..afac4eb 100644 --- a/clickstream/src/main/java/software/aws/solution/clickstream/client/Event.java +++ b/clickstream/src/main/java/software/aws/solution/clickstream/client/Event.java @@ -152,8 +152,11 @@ private ErrorCode() { * Event for return. */ public static class EventError { - private final int errorCode; - private final String errorMessage; + private int errorCode; + private String errorMessage; + + EventError() { + } EventError(int errorType, String errorMessage) { this.errorCode = errorType; @@ -178,6 +181,23 @@ public String getErrorMessage() { return errorMessage; } + /** + * set error code. + * + * @param errorCode the error code + */ + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } + + /** + * set error message. + * + * @param errorMessage the error message + */ + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } } /** diff --git a/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java b/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java index 875e5d7..a2b2e1d 100644 --- a/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java +++ b/clickstream/src/main/java/software/aws/solution/clickstream/client/EventChecker.java @@ -48,16 +48,18 @@ private EventChecker() { * @return the EventError object */ public static EventError checkEventName(String eventName) { + EventError error = new EventError(); + error.setErrorCode(ErrorCode.NO_ERROR); if (!isValidName(eventName)) { - return new EventError(ErrorCode.EVENT_NAME_INVALID, - "Event name can only contains uppercase and lowercase letters, " + - "underscores, number, and is not start with a number. event name: " + eventName); + error.setErrorCode(ErrorCode.EVENT_NAME_INVALID); + error.setErrorMessage("Event name can only contains uppercase and lowercase letters, " + + "underscores, number, and is not start with a number. event name: " + eventName); } else if (eventName.length() > Limit.MAX_LENGTH_OF_NAME) { - return new EventError(ErrorCode.EVENT_NAME_LENGTH_EXCEED, - "Event name is too long, the max event type length is " + - Limit.MAX_LENGTH_OF_NAME + "characters. event name: " + eventName); + error.setErrorCode(ErrorCode.EVENT_NAME_LENGTH_EXCEED); + error.setErrorMessage("Event name is too long, the max event type length is " + + Limit.MAX_LENGTH_OF_NAME + "characters. event name: " + eventName); } - return new EventError(ErrorCode.NO_ERROR, ""); + return error; } /** @@ -81,41 +83,44 @@ public static Boolean isValidName(String name) { * @return the ErrorType */ public static EventError checkAttribute(int currentNumber, String name, Object value) { + EventError error = new EventError(); + error.setErrorCode(ErrorCode.NO_ERROR); + String errorMsg = null; if (currentNumber >= Limit.MAX_NUM_OF_ATTRIBUTES) { - LOG.error("reached the max number of attributes limit (" - + Limit.MAX_NUM_OF_ATTRIBUTES + "). and the attribute: " + name + " will not be recorded"); - return new EventError(ErrorCode.ATTRIBUTE_SIZE_EXCEED, + errorMsg = "reached the max number of attributes limit (" + + Limit.MAX_NUM_OF_ATTRIBUTES + "). and the attribute: " + name + " will not be recorded"; + error.setErrorCode(ErrorCode.ATTRIBUTE_SIZE_EXCEED); + error.setErrorMessage( StringUtil.clipString("attribute name: " + name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); - } - if (name.length() > Limit.MAX_LENGTH_OF_NAME) { - LOG.error("attribute : " + name + ", reached the max length of attributes name limit(" + } else if (name.length() > Limit.MAX_LENGTH_OF_NAME) { + errorMsg = "attribute : " + name + ", reached the max length of attributes name limit(" + Limit.MAX_LENGTH_OF_NAME + "). current length is:(" + name.length() + - ") and the attribute will not be recorded"); - return new EventError(ErrorCode.ATTRIBUTE_NAME_LENGTH_EXCEED, + ") and the attribute will not be recorded"; + error.setErrorCode(ErrorCode.ATTRIBUTE_NAME_LENGTH_EXCEED); + error.setErrorMessage( StringUtil.clipString("attribute name length is:(" + name.length() + ") name is:" + name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); - } - if (!isValidName(name)) { - LOG.error("attribute : " + name + ", was not valid, attribute name can only contains" + + } else if (!isValidName(name)) { + errorMsg = "attribute : " + name + ", was not valid, attribute name can only contains" + " uppercase and lowercase letters, underscores, number, and is not start with a number." + - " so the attribute will not be recorded"); - return new EventError(ErrorCode.ATTRIBUTE_NAME_INVALID, - StringUtil.clipString(name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); - } - - if (value instanceof String) { + " so the attribute will not be recorded"; + error.setErrorCode(ErrorCode.ATTRIBUTE_NAME_INVALID); + error.setErrorMessage(StringUtil.clipString(name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); + } else if (value instanceof String) { int valueLength = ((String) value).length(); if (valueLength > Limit.MAX_LENGTH_OF_VALUE) { - LOG.error("attribute : " + name + ", reached the max length of attributes value limit (" + errorMsg = "attribute : " + name + ", reached the max length of attributes value limit (" + Limit.MAX_LENGTH_OF_VALUE + "). current length is:(" + valueLength + - "). and the attribute will not be recorded, attribute value:" + value); - - return new EventError(ErrorCode.ATTRIBUTE_VALUE_LENGTH_EXCEED, - StringUtil.clipString("attribute name:" + name + ", attribute value:" + value, - Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); + "). and the attribute will not be recorded, attribute value:" + value; + error.setErrorCode(ErrorCode.ATTRIBUTE_VALUE_LENGTH_EXCEED); + error.setErrorMessage(StringUtil.clipString("attribute name:" + name + ", attribute value:" + value, + Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); } } - return new EventError(ErrorCode.NO_ERROR, ""); + if (errorMsg != null) { + LOG.warn(errorMsg); + } + return error; } /** @@ -127,39 +132,45 @@ public static EventError checkAttribute(int currentNumber, String name, Object v * @return the ErrorType */ public static EventError checkUserAttribute(int currentNumber, String name, Object value) { + EventError error = new EventError(); + error.setErrorCode(ErrorCode.NO_ERROR); + String errorMsg = null; if (currentNumber >= Limit.MAX_NUM_OF_USER_ATTRIBUTES) { - LOG.error("reached the max number of user attributes limit (" - + Limit.MAX_NUM_OF_USER_ATTRIBUTES + "). and the user attribute: " + name + " will not be recorded"); - return new EventError(ErrorCode.USER_ATTRIBUTE_SIZE_EXCEED, + errorMsg = "reached the max number of user attributes limit (" + + Limit.MAX_NUM_OF_USER_ATTRIBUTES + "). and the user attribute: " + name + " will not be recorded"; + error.setErrorCode(ErrorCode.USER_ATTRIBUTE_SIZE_EXCEED); + error.setErrorMessage( StringUtil.clipString("attribute name: " + name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); - } - if (name.length() > Limit.MAX_LENGTH_OF_NAME) { - LOG.error("user attribute : " + name + ", reached the max length of attributes name limit(" + } else if (name.length() > Limit.MAX_LENGTH_OF_NAME) { + errorMsg = "user attribute : " + name + ", reached the max length of attributes name limit(" + Limit.MAX_LENGTH_OF_NAME + "). current length is:(" + name.length() + - ") and the attribute will not be recorded"); - return new EventError(ErrorCode.USER_ATTRIBUTE_NAME_LENGTH_EXCEED, + ") and the attribute will not be recorded"; + error.setErrorCode(ErrorCode.USER_ATTRIBUTE_NAME_LENGTH_EXCEED); + error.setErrorMessage( StringUtil.clipString("user attribute name length is:(" + name.length() + ") name is:" + name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); - } - if (!isValidName(name)) { - LOG.error("user attribute : " + name + ", was not valid, user attribute name can only contains" + + } else if (!isValidName(name)) { + errorMsg = "user attribute : " + name + ", was not valid, user attribute name can only contains" + " uppercase and lowercase letters, underscores, number, and is not start with a number." + - " so the attribute will not be recorded"); - return new EventError(ErrorCode.USER_ATTRIBUTE_NAME_INVALID, - StringUtil.clipString(name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); - } - if (value instanceof String) { + " so the attribute will not be recorded"; + error.setErrorCode(ErrorCode.USER_ATTRIBUTE_NAME_INVALID); + error.setErrorMessage(StringUtil.clipString(name, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); + } else if (value instanceof String) { int valueLength = ((String) value).length(); if (valueLength > Limit.MAX_LENGTH_OF_USER_VALUE) { - LOG.error("user attribute : " + name + ", reached the max length of attributes value limit (" + errorMsg = "user attribute : " + name + ", reached the max length of attributes value limit (" + Limit.MAX_LENGTH_OF_USER_VALUE + "). current length is:(" + valueLength + - "). and the attribute will not be recorded, attribute value:" + value); - return new EventError(ErrorCode.USER_ATTRIBUTE_VALUE_LENGTH_EXCEED, + "). and the attribute will not be recorded, attribute value:" + value; + error.setErrorCode(ErrorCode.USER_ATTRIBUTE_VALUE_LENGTH_EXCEED); + error.setErrorMessage( StringUtil.clipString("user attribute name:" + name + ", attribute value:" + value, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); } } - return new EventError(ErrorCode.NO_ERROR, ""); + if (errorMsg != null) { + LOG.warn(errorMsg); + } + return error; } /** @@ -177,61 +188,65 @@ public static EventError checkItemAttribute(int currentNumber, ClickstreamItem i String itemKey = item.getAttributes().toString(); String errorMsg = "reached the max number of items limit" + Event.Limit.MAX_NUM_OF_ITEMS + ". and the item: " + itemKey + " will not be recorded"; - LOG.error(errorMsg); + LOG.warn(errorMsg); return new EventError(ErrorCode.ITEM_SIZE_EXCEED, StringUtil.clipString(errorMsg, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); } int customKeyNumber = 0; Iterator keys = item.getAttributes().keys(); + EventError error = new EventError(); + error.setErrorCode(ErrorCode.NO_ERROR); + String errorMsg = null; while (keys.hasNext()) { String key = keys.next(); String valueStr = ""; try { valueStr = item.getAttributes().get(key).toString(); } catch (JSONException exception) { - LOG.error("error getting item value for key: " + key + ", error message: " + exception.getMessage()); + LOG.warn("error getting item value for key: " + key + ", error message: " + exception.getMessage()); } - EventError attributeError = null; if (!itemKeySet.contains(key)) { customKeyNumber += 1; if (customKeyNumber > Limit.MAX_NUM_OF_CUSTOM_ITEM_ATTRIBUTE) { - LOG.error("reached the max number of custom item attributes limit (" + errorMsg = "reached the max number of custom item attributes limit (" + Limit.MAX_NUM_OF_CUSTOM_ITEM_ATTRIBUTE + "). and the custom item attribute: " + key + - " will not be recorded"); - attributeError = new EventError(ErrorCode.ITEM_CUSTOM_ATTRIBUTE_SIZE_EXCEED, + " will not be recorded"; + error.setErrorCode(ErrorCode.ITEM_CUSTOM_ATTRIBUTE_SIZE_EXCEED); + error.setErrorMessage( StringUtil.clipString("item attribute key: " + key, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); } else if (key.length() > Limit.MAX_LENGTH_OF_NAME) { - LOG.error("item attribute key: " + key + ", reached the max length of item attributes key limit(" + errorMsg = "item attribute key: " + key + ", reached the max length of item attributes key limit(" + Limit.MAX_LENGTH_OF_NAME + "). current length is:(" + key.length() + - ") and the item attribute will not be recorded"); - attributeError = new EventError(ErrorCode.ITEM_CUSTOM_ATTRIBUTE_KEY_LENGTH_EXCEED, + ") and the item attribute will not be recorded"; + error.setErrorCode(ErrorCode.ITEM_CUSTOM_ATTRIBUTE_KEY_LENGTH_EXCEED); + error.setErrorMessage( StringUtil.clipString("item attribute key length is:(" + key.length() + ") key is:" + key, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); } else if (!isValidName(key)) { - LOG.error("item attribute key: " + key + ", was not valid, item attribute key can only contains" + + errorMsg = "item attribute key: " + key + ", was not valid, item attribute key can only contains" + " uppercase and lowercase letters, underscores, number, and is not start with a number." + - " so the item attribute will not be recorded"); - attributeError = new EventError(ErrorCode.ITEM_CUSTOM_ATTRIBUTE_KEY_INVALID, - StringUtil.clipString(key, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); + " so the item attribute will not be recorded"; + error.setErrorCode(ErrorCode.ITEM_CUSTOM_ATTRIBUTE_KEY_INVALID); + error.setErrorMessage(StringUtil.clipString(key, Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); } } - if (attributeError == null && valueStr.length() > Limit.MAX_LENGTH_OF_ITEM_VALUE) { - String errorMsg = + if (error.getErrorCode() == ErrorCode.NO_ERROR && valueStr.length() > Limit.MAX_LENGTH_OF_ITEM_VALUE) { + errorMsg = "item attribute : " + key + ", reached the max length of item attribute value limit (" + Limit.MAX_LENGTH_OF_ITEM_VALUE + "). current length is: (" + valueStr.length() + "). and the item attribute will not be recorded, attribute value: " + valueStr; - LOG.error(errorMsg); String errorString = "item attribute name: " + key + ", item attribute value: " + valueStr; - attributeError = - new EventError(ErrorCode.ITEM_ATTRIBUTE_VALUE_LENGTH_EXCEED, StringUtil.clipString(errorString, - Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); + error.setErrorCode(ErrorCode.ITEM_ATTRIBUTE_VALUE_LENGTH_EXCEED); + error.setErrorMessage(StringUtil.clipString(errorString, + Limit.MAX_LENGTH_OF_ERROR_VALUE, true)); } - if (attributeError != null) { - return attributeError; + if (error.getErrorCode() > 0) { + LOG.warn(errorMsg); + return error; } } - return new EventError(ErrorCode.NO_ERROR, ""); + return error; } private static void initItemKeySet() { From b4c209bbd2419d678ea51aae64783f619ff92716 Mon Sep 17 00:00:00 2001 From: xiaoweii Date: Fri, 8 Dec 2023 13:31:49 +0800 Subject: [PATCH 7/8] fix: resolve conflicts --- .../aws/solution/clickstream/client/AnalyticsClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsClient.java b/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsClient.java index 77d196f..7837e2f 100644 --- a/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsClient.java +++ b/clickstream/src/main/java/software/aws/solution/clickstream/client/AnalyticsClient.java @@ -101,7 +101,7 @@ public void deleteGlobalAttribute(String name) { */ public void addUserAttribute(String name, Object value) { if (value != null) { - Event.EventError error = EventChecker.checkUserAttribute(userAttributes.length(), name, value); + Event.EventError error = EventChecker.checkUserAttribute(allUserAttributes.length(), name, value); if (error.getErrorCode() > 0) { final AnalyticsEvent event = createEvent(Event.PresetEvent.CLICKSTREAM_ERROR); event.addAttribute(Event.ReservedAttribute.ERROR_CODE, error.getErrorCode()); From eb0503f1b115b50a4d11ab376da088f0ab273a39 Mon Sep 17 00:00:00 2001 From: xiaoweii Date: Tue, 12 Dec 2023 08:46:07 +0800 Subject: [PATCH 8/8] fix: update Documentation site link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c2d4efc..d9353ec 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Clickstream Android SDK can help you easily collect and report in-app events fro The SDK relies on the Amplify for Android SDK Core Library and is developed according to the Amplify Android SDK plug-in specification. In addition, we've added features that automatically collect common user events and attributes (e.g., screen view, first open) to simplify data collection for users. -Visit our [Documentation site](https://awslabs.github.io/clickstream-analytics-on-aws/en/sdk-manual/android/) to learn more about Clickstream Android SDK. +Visit our [Documentation site](https://awslabs.github.io/clickstream-analytics-on-aws/en/latest/sdk-manual/android/) to learn more about Clickstream Android SDK. ### Platform Support