diff --git a/src/main/java/com/snowplowanalytics/snowplow/tracker/Snowplow.java b/src/main/java/com/snowplowanalytics/snowplow/tracker/Snowplow.java new file mode 100644 index 00000000..bc99c784 --- /dev/null +++ b/src/main/java/com/snowplowanalytics/snowplow/tracker/Snowplow.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2014-2022 Snowplow Analytics Ltd. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package com.snowplowanalytics.snowplow.tracker; + +import com.snowplowanalytics.snowplow.tracker.configuration.EmitterConfiguration; +import com.snowplowanalytics.snowplow.tracker.configuration.NetworkConfiguration; +import com.snowplowanalytics.snowplow.tracker.configuration.SubjectConfiguration; +import com.snowplowanalytics.snowplow.tracker.configuration.TrackerConfiguration; +import com.snowplowanalytics.snowplow.tracker.emitter.BatchEmitter; +import com.snowplowanalytics.snowplow.tracker.emitter.Emitter; + +import java.util.HashMap; +import java.util.Map; + +public class Snowplow { + + private static final Map trackers = new HashMap<>(); + private static Tracker defaultTracker; + + public static Map getTrackers() { + return trackers; + } + + public static Tracker getDefaultTracker() { + return defaultTracker; + } + + public static void setDefaultTracker(Tracker tracker) { + defaultTracker = tracker; + } + + public static Tracker createTracker(String collectorUrl, String namespace, String appId) { + BatchEmitter emitter = BatchEmitter.builder().url(collectorUrl).build(); + Tracker tracker = new Tracker.TrackerBuilder(emitter, namespace, appId).build(); + registerTracker(tracker); + return tracker; + } + + public static Tracker createTracker(TrackerConfiguration trackerConfig, + NetworkConfiguration networkConfig, + EmitterConfiguration emitterConfig, + SubjectConfiguration subjectConfig) { + BatchEmitter emitter = new BatchEmitter(networkConfig, emitterConfig); + Subject subject = new Subject(subjectConfig); + Tracker tracker = new Tracker(trackerConfig, emitter, subject); + registerTracker(tracker); + return tracker; + } + + public static Tracker createTracker(TrackerConfiguration trackerConfig, + NetworkConfiguration networkConfig, + EmitterConfiguration emitterConfig) { + return createTracker(trackerConfig, networkConfig, emitterConfig, new SubjectConfiguration()); + } + + public static Tracker createTracker(TrackerConfiguration trackerConfig, + NetworkConfiguration networkConfig) { + return createTracker(trackerConfig, networkConfig, new EmitterConfiguration(), new SubjectConfiguration()); + } + + public static Tracker createTracker(TrackerConfiguration trackerConfig, + NetworkConfiguration networkConfig, + SubjectConfiguration subjectConfig) { + return createTracker(trackerConfig, networkConfig, new EmitterConfiguration(), subjectConfig); + } + + public static void registerTracker(Tracker tracker) { + String namespace = tracker.getNamespace(); + if (trackers.containsKey(namespace)) { + throw new IllegalArgumentException("Tracker with this namespace already exists."); + } + + trackers.put(namespace, tracker); + + if (defaultTracker == null) { + defaultTracker = tracker; + } + } + + public static Tracker getTracker(String namespace) { + return trackers.get(namespace); + } + + public static boolean removeTracker(String namespace) { + Tracker removedTracker = trackers.remove(namespace); + if ((defaultTracker != null) && defaultTracker.getNamespace().equals(namespace)) { + defaultTracker = null; + } + return removedTracker != null; + } + + public static boolean removeTracker(Tracker tracker) { + return removeTracker(tracker.getNamespace()); + } + + public static void reset() { + trackers.clear(); + defaultTracker = null; + } +} diff --git a/src/main/java/com/snowplowanalytics/snowplow/tracker/Subject.java b/src/main/java/com/snowplowanalytics/snowplow/tracker/Subject.java index fb803f9a..454ec5dd 100644 --- a/src/main/java/com/snowplowanalytics/snowplow/tracker/Subject.java +++ b/src/main/java/com/snowplowanalytics/snowplow/tracker/Subject.java @@ -17,6 +17,7 @@ import java.util.Map; // This library +import com.snowplowanalytics.snowplow.tracker.configuration.SubjectConfiguration; import com.snowplowanalytics.snowplow.tracker.constants.Parameter; /** @@ -28,23 +29,18 @@ public class Subject { private HashMap standardPairs = new HashMap<>(); - /** - * Creates a Subject which will add extra data to each event. - * - * @param builder The builder that constructs a subject - */ - private Subject(SubjectBuilder builder) { - this.setUserId(builder.userId); - this.setScreenResolution(builder.screenResWidth, builder.screenResHeight); - this.setViewPort(builder.viewPortWidth, builder.viewPortHeight); - this.setColorDepth(builder.colorDepth); - this.setTimezone(builder.timezone); - this.setLanguage(builder.language); - this.setIpAddress(builder.ipAddress); - this.setUseragent(builder.useragent); - this.setNetworkUserId(builder.networkUserId); - this.setDomainUserId(builder.domainUserId); - this.setDomainSessionId(builder.domainSessionId); + public Subject(SubjectConfiguration subjectConfig) { + setUserId(subjectConfig.getUserId()); + setScreenResolution(subjectConfig.getScreenResWidth(), subjectConfig.getScreenResHeight()); + setViewPort(subjectConfig.getViewPortWidth(), subjectConfig.getViewPortHeight()); + setColorDepth(subjectConfig.getColorDepth()); + setTimezone(subjectConfig.getTimezone()); + setLanguage(subjectConfig.getLanguage()); + setIpAddress(subjectConfig.getIpAddress()); + setUseragent(subjectConfig.getUseragent()); + setNetworkUserId(subjectConfig.getNetworkUserId()); + setDomainUserId(subjectConfig.getDomainUserId()); + setDomainSessionId(subjectConfig.getDomainSessionId()); } /** @@ -185,7 +181,22 @@ public SubjectBuilder domainSessionId(String domainSessionId) { * @return a new Subject object */ public Subject build() { - return new Subject(this); + SubjectConfiguration subjectConfig = new SubjectConfiguration(); + + +// setUserId(subjectConfig.getUserId()); +// setScreenResolution(subjectConfig.getScreenResWidth(), subjectConfig.getScreenResHeight()); +// setViewPort(subjectConfig.getViewPortWidth(), subjectConfig.getViewPortHeight()); +// setColorDepth(subjectConfig.getColorDepth()); +// setTimezone(subjectConfig.getTimezone()); +// setLanguage(subjectConfig.getLanguage()); +// setIpAddress(subjectConfig.getIpAddress()); +// setUseragent(subjectConfig.getUseragent()); +// setNetworkUserId(subjectConfig.getNetworkUserId()); +// setDomainUserId(subjectConfig.getDomainUserId()); +// setDomainSessionId(subjectConfig.getDomainSessionId()); + + return new Subject(subjectConfig); } } diff --git a/src/main/java/com/snowplowanalytics/snowplow/tracker/Tracker.java b/src/main/java/com/snowplowanalytics/snowplow/tracker/Tracker.java index c9d69872..d1a1538c 100644 --- a/src/main/java/com/snowplowanalytics/snowplow/tracker/Tracker.java +++ b/src/main/java/com/snowplowanalytics/snowplow/tracker/Tracker.java @@ -14,6 +14,7 @@ import com.google.common.base.Preconditions; +import com.snowplowanalytics.snowplow.tracker.configuration.TrackerConfiguration; import com.snowplowanalytics.snowplow.tracker.constants.Constants; import com.snowplowanalytics.snowplow.tracker.constants.Parameter; import com.snowplowanalytics.snowplow.tracker.emitter.Emitter; @@ -38,18 +39,24 @@ public class Tracker { * * @param builder The builder that constructs a tracker */ - private Tracker(TrackerBuilder builder) { + + + public Tracker(TrackerConfiguration trackerConfig, Emitter emitter) { + this(trackerConfig, emitter, new Subject.SubjectBuilder().build()); + } + + public Tracker(TrackerConfiguration trackerConfig, Emitter emitter, Subject subject) { // Precondition checks - Preconditions.checkNotNull(builder.emitter); - Preconditions.checkNotNull(builder.namespace); - Preconditions.checkNotNull(builder.appId); - Preconditions.checkArgument(!builder.namespace.isEmpty(), "namespace cannot be empty"); - Preconditions.checkArgument(!builder.appId.isEmpty(), "appId cannot be empty"); + Preconditions.checkNotNull(emitter); + Preconditions.checkNotNull(trackerConfig.getNamespace()); + Preconditions.checkNotNull(trackerConfig.getAppId()); + Preconditions.checkArgument(!trackerConfig.getNamespace().isEmpty(), "namespace cannot be empty"); + Preconditions.checkArgument(!trackerConfig.getAppId().isEmpty(), "appId cannot be empty"); - this.parameters = new TrackerParameters(builder.appId, builder.platform, builder.namespace, Version.TRACKER, builder.base64Encoded); - this.emitter = builder.emitter; - this.subject = builder.subject; + this.parameters = new TrackerParameters(trackerConfig.getAppId(), trackerConfig.getPlatform(), trackerConfig.getNamespace(), Version.TRACKER, trackerConfig.isBase64Encoded()); + this.emitter = emitter; + this.subject = subject; } @@ -113,7 +120,10 @@ public TrackerBuilder base64(Boolean base64) { * @return a new Tracker object */ public Tracker build() { - return new Tracker(this); + TrackerConfiguration trackerConfig = new TrackerConfiguration(namespace, appId) + .platform(platform) + .base64Encoded(base64Encoded); + return new Tracker(trackerConfig, emitter, subject); } } diff --git a/src/main/java/com/snowplowanalytics/snowplow/tracker/configuration/EmitterConfiguration.java b/src/main/java/com/snowplowanalytics/snowplow/tracker/configuration/EmitterConfiguration.java new file mode 100644 index 00000000..1e1cfdee --- /dev/null +++ b/src/main/java/com/snowplowanalytics/snowplow/tracker/configuration/EmitterConfiguration.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2014-2022 Snowplow Analytics Ltd. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package com.snowplowanalytics.snowplow.tracker.configuration; + +import com.snowplowanalytics.snowplow.tracker.emitter.EventStore; + +import java.util.List; +import java.util.concurrent.ScheduledExecutorService; + +public class EmitterConfiguration { + + private int batchSize; // Optional + private int bufferCapacity; // Optional + private EventStore eventStore; // Optional + private List fatalResponseCodes; // Optional + private int threadCount; // Optional + private ScheduledExecutorService requestExecutorService; // Optional + + // Getters and Setters + + public int getBatchSize() { + return batchSize; + } + + public void setBatchSize(int batchSize) { + this.batchSize = batchSize; + } + + public int getBufferCapacity() { + return bufferCapacity; + } + + public void setBufferCapacity(int bufferCapacity) { + this.bufferCapacity = bufferCapacity; + } + + public EventStore getEventStore() { + return eventStore; + } + + public void setEventStore(EventStore eventStore) { + this.eventStore = eventStore; + } + + public List getFatalResponseCodes() { + return fatalResponseCodes; + } + + public void setFatalResponseCodes(List fatalResponseCodes) { + this.fatalResponseCodes = fatalResponseCodes; + } + + public int getThreadCount() { + return threadCount; + } + + public void setThreadCount(int threadCount) { + this.threadCount = threadCount; + } + + public ScheduledExecutorService getRequestExecutorService() { + return requestExecutorService; + } + + public void setRequestExecutorService(ScheduledExecutorService requestExecutorService) { + this.requestExecutorService = requestExecutorService; + } + + // Constructor + + public EmitterConfiguration() { + batchSize = 50; + bufferCapacity = Integer.MAX_VALUE; + eventStore = null; + fatalResponseCodes = null; + threadCount = 50; + requestExecutorService = null; + } + + // Builder methods + + public EmitterConfiguration batchSize(int batchSize) { + this.batchSize = batchSize; + return this; + } + + public EmitterConfiguration bufferCapacity(int bufferCapacity) { + this.bufferCapacity = bufferCapacity; + return this; + } + + public EmitterConfiguration eventStore(EventStore eventStore) { + this.eventStore = eventStore; + return this; + } + + public EmitterConfiguration fatalResponseCodes(List fatalResponseCodes) { + this.fatalResponseCodes = fatalResponseCodes; + return this; + } + + public EmitterConfiguration threadCount(int threadCount) { + this.threadCount = threadCount; + return this; + } + + public EmitterConfiguration requestExecutorService(ScheduledExecutorService requestExecutorService) { + this.requestExecutorService = requestExecutorService; + return this; + } +} diff --git a/src/main/java/com/snowplowanalytics/snowplow/tracker/configuration/NetworkConfiguration.java b/src/main/java/com/snowplowanalytics/snowplow/tracker/configuration/NetworkConfiguration.java new file mode 100644 index 00000000..8a7c2410 --- /dev/null +++ b/src/main/java/com/snowplowanalytics/snowplow/tracker/configuration/NetworkConfiguration.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014-2022 Snowplow Analytics Ltd. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package com.snowplowanalytics.snowplow.tracker.configuration; + +import com.snowplowanalytics.snowplow.tracker.http.HttpClientAdapter; +import okhttp3.CookieJar; + + +public class NetworkConfiguration { + + private HttpClientAdapter httpClientAdapter; // Optional + private String collectorUrl; // Required if not specifying a httpClientAdapter + private CookieJar cookieJar; // Optional + + // Getters and Setters + + public HttpClientAdapter getHttpClientAdapter() { + return httpClientAdapter; + } + + public void setHttpClientAdapter(HttpClientAdapter httpClientAdapter) { + this.httpClientAdapter = httpClientAdapter; + } + + public String getCollectorUrl() { + return collectorUrl; + } + + public void setCollectorUrl(String collectorUrl) { + this.collectorUrl = collectorUrl; + } + + public CookieJar getCookieJar() { + return cookieJar; + } + + public void setCookieJar(CookieJar cookieJar) { + this.cookieJar = cookieJar; + } + + // Constructor + + public NetworkConfiguration() { + httpClientAdapter = null; + collectorUrl = null; + cookieJar = null; + } + + // Builder methods + + public NetworkConfiguration httpClientAdapter(HttpClientAdapter httpClientAdapter) { + this.httpClientAdapter = httpClientAdapter; + return this; + } + + public NetworkConfiguration collectorUrl(String collectorUrl) { + this.collectorUrl = collectorUrl; + return this; + } + + public NetworkConfiguration cookieJar(CookieJar cookieJar) { + this.cookieJar = cookieJar; + return this; + } +} diff --git a/src/main/java/com/snowplowanalytics/snowplow/tracker/configuration/SubjectConfiguration.java b/src/main/java/com/snowplowanalytics/snowplow/tracker/configuration/SubjectConfiguration.java new file mode 100644 index 00000000..987d5c97 --- /dev/null +++ b/src/main/java/com/snowplowanalytics/snowplow/tracker/configuration/SubjectConfiguration.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2014-2022 Snowplow Analytics Ltd. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package com.snowplowanalytics.snowplow.tracker.configuration; + +import com.snowplowanalytics.snowplow.tracker.Utils; + +public class SubjectConfiguration { + + private String userId; // Optional + private int screenResWidth; // Optional + private int screenResHeight; // Optional + private int viewPortWidth; // Optional + private int viewPortHeight; // Optional + private int colorDepth; // Optional + private String timezone; // Optional + private String language; // Optional + private String ipAddress; // Optional + private String useragent; // Optional + private String networkUserId; // Optional + private String domainUserId; // Optional + private String domainSessionId; // Optional + + // Getters and Setters + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public int getScreenResWidth() { + return screenResWidth; + } + + public void setScreenResWidth(int screenResWidth) { + this.screenResWidth = screenResWidth; + } + + public int getScreenResHeight() { + return screenResHeight; + } + + public void setScreenResHeight(int screenResHeight) { + this.screenResHeight = screenResHeight; + } + + public int getViewPortWidth() { + return viewPortWidth; + } + + public void setViewPortWidth(int viewPortWidth) { + this.viewPortWidth = viewPortWidth; + } + + public int getViewPortHeight() { + return viewPortHeight; + } + + public void setViewPortHeight(int viewPortHeight) { + this.viewPortHeight = viewPortHeight; + } + + public int getColorDepth() { + return colorDepth; + } + + public void setColorDepth(int colorDepth) { + this.colorDepth = colorDepth; + } + + public String getTimezone() { + return timezone; + } + + public void setTimezone(String timezone) { + this.timezone = timezone; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public String getUseragent() { + return useragent; + } + + public void setUseragent(String useragent) { + this.useragent = useragent; + } + + public String getNetworkUserId() { + return networkUserId; + } + + public void setNetworkUserId(String networkUserId) { + this.networkUserId = networkUserId; + } + + public String getDomainUserId() { + return domainUserId; + } + + public void setDomainUserId(String domainUserId) { + this.domainUserId = domainUserId; + } + + public String getDomainSessionId() { + return domainSessionId; + } + + public void setDomainSessionId(String domainSessionId) { + this.domainSessionId = domainSessionId; + } + + + // Constructor + + public SubjectConfiguration() { + userId = null; // Optional + screenResWidth = 0; // Optional + screenResHeight = 0; // Optional + viewPortWidth = 0; // Optional + viewPortHeight = 0; // Optional + colorDepth = 0; // Optional + timezone = Utils.getTimezone(); // Optional + language = null; // Optional + ipAddress = null; // Optional + useragent = null; // Optional + networkUserId = null; // Optional + domainUserId = null; // Optional + domainSessionId = null; // Optional + } + + // Builder methods + + public SubjectConfiguration userId(String userId) { + this.userId = userId; + return this; + } + + public SubjectConfiguration screenResolution(int width, int height) { + screenResWidth = width; + screenResHeight = height; + return this; + } + + public SubjectConfiguration viewPort(int width, int height) { + viewPortWidth = width; + viewPortHeight = height; + return this; + } + + /** + * @param depth a color depth integer + * @return itself + */ + public SubjectConfiguration colorDepth(int depth) { + colorDepth = depth; + return this; + } + + /** + * Note that timezone is set by default to the server's timezone + * (`TimeZone tz = Calendar.getInstance().getTimeZone().getID()`) + * @param timezone a timezone string + * @return itself + */ + public SubjectConfiguration timezone(String timezone) { + this.timezone = timezone; + return this; + } + + /** + * @param language a language string + * @return itself + */ + public SubjectConfiguration language(String language) { + this.language = language; + return this; + } + + /** + * @param ipAddress a ipAddress string + * @return itself + */ + public SubjectConfiguration ipAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + /** + * @param useragent a useragent string + * @return itself + */ + public SubjectConfiguration useragent(String useragent) { + this.useragent = useragent; + return this; + } + + /** + * @param networkUserId a networkUserId string + * @return itself + */ + public SubjectConfiguration networkUserId(String networkUserId) { + this.networkUserId = networkUserId; + return this; + } + + /** + * @param domainUserId a domainUserId string + * @return itself + */ + public SubjectConfiguration domainUserId(String domainUserId) { + this.domainUserId = domainUserId; + return this; + } + + /** + * @param domainSessionId a domainSessionId string + * @return itself + */ + public SubjectConfiguration domainSessionId(String domainSessionId) { + this.domainSessionId = domainSessionId; + return this; + } +} diff --git a/src/main/java/com/snowplowanalytics/snowplow/tracker/configuration/TrackerConfiguration.java b/src/main/java/com/snowplowanalytics/snowplow/tracker/configuration/TrackerConfiguration.java new file mode 100644 index 00000000..189d8e19 --- /dev/null +++ b/src/main/java/com/snowplowanalytics/snowplow/tracker/configuration/TrackerConfiguration.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014-2022 Snowplow Analytics Ltd. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package com.snowplowanalytics.snowplow.tracker.configuration; + +import com.snowplowanalytics.snowplow.tracker.DevicePlatform; + + +public class TrackerConfiguration { + private final String namespace; // Required + private final String appId; // Required + private DevicePlatform platform; // Optional + private boolean base64Encoded; // Optional + + // Getters and Setters + + public String getNamespace() { + return namespace; + } + + public String getAppId() { + return appId; + } + + public DevicePlatform getPlatform() { + return platform; + } + + public void setPlatform(DevicePlatform platform) { + this.platform = platform; + } + + public boolean isBase64Encoded() { + return base64Encoded; + } + + public void setBase64Encoded(boolean base64Encoded) { + this.base64Encoded = base64Encoded; + } + + // Constructor + + public TrackerConfiguration(String namespace, String appId) { + this.namespace = namespace; + this.appId = appId; + this.platform = DevicePlatform.ServerSideApp; + this.base64Encoded = true; + } + + // Builder methods + + public TrackerConfiguration platform(DevicePlatform platform) { + this.platform = platform; + return this; + } + + public TrackerConfiguration base64Encoded(boolean base64Encoded) { + this.base64Encoded = base64Encoded; + return this; + } +} diff --git a/src/main/java/com/snowplowanalytics/snowplow/tracker/emitter/BatchEmitter.java b/src/main/java/com/snowplowanalytics/snowplow/tracker/emitter/BatchEmitter.java index 645f4da5..567f3234 100644 --- a/src/main/java/com/snowplowanalytics/snowplow/tracker/emitter/BatchEmitter.java +++ b/src/main/java/com/snowplowanalytics/snowplow/tracker/emitter/BatchEmitter.java @@ -23,6 +23,8 @@ import java.util.concurrent.atomic.AtomicInteger; import com.google.common.base.Preconditions; +import com.snowplowanalytics.snowplow.tracker.configuration.EmitterConfiguration; +import com.snowplowanalytics.snowplow.tracker.configuration.NetworkConfiguration; import com.snowplowanalytics.snowplow.tracker.constants.Constants; import com.snowplowanalytics.snowplow.tracker.constants.Parameter; import com.snowplowanalytics.snowplow.tracker.http.HttpClientAdapter; @@ -184,7 +186,20 @@ public T cookieJar(final CookieJar cookieJar) { } public BatchEmitter build() { - return new BatchEmitter(this); + NetworkConfiguration networkConfig = new NetworkConfiguration() + .collectorUrl(collectorUrl) + .httpClientAdapter(httpClientAdapter) + .cookieJar(cookieJar); + + EmitterConfiguration emitterConfig = new EmitterConfiguration() + .batchSize(batchSize) + .bufferCapacity(bufferCapacity) + .eventStore(eventStore) + .fatalResponseCodes(fatalResponseCodes) + .threadCount(threadCount) + .requestExecutorService(requestExecutorService); + + return new BatchEmitter(networkConfig, emitterConfig); } } @@ -199,54 +214,58 @@ public static Builder builder() { return new Builder2(); } - protected BatchEmitter(final Builder builder) { + public BatchEmitter(NetworkConfiguration networkConfig, EmitterConfiguration emitterConfig) { OkHttpClient client; // Precondition checks - Preconditions.checkArgument(builder.threadCount > 0, "threadCount must be greater than 0"); - Preconditions.checkArgument(builder.batchSize > 0, "batchSize must be greater than 0"); + Preconditions.checkArgument(emitterConfig.getThreadCount() > 0, "threadCount must be greater than 0"); + Preconditions.checkArgument(emitterConfig.getBatchSize() > 0, "batchSize must be greater than 0"); - if (builder.httpClientAdapter != null) { - httpClientAdapter = builder.httpClientAdapter; + if (networkConfig.getHttpClientAdapter() != null) { + httpClientAdapter = networkConfig.getHttpClientAdapter(); } else { - Preconditions.checkNotNull(builder.collectorUrl, "Collector url must be specified if not using a httpClientAdapter"); + Preconditions.checkNotNull(networkConfig.getCollectorUrl(), "Collector url must be specified if not using a httpClientAdapter"); - if (builder.cookieJar != null) { + if (networkConfig.getCookieJar() != null) { client = new OkHttpClient.Builder() - .cookieJar(builder.cookieJar) + .cookieJar(networkConfig.getCookieJar()) .build(); } else { client = new OkHttpClient.Builder().build(); } httpClientAdapter = OkHttpClientAdapter.builder() // use okhttp as a default - .url(builder.collectorUrl) + .url(networkConfig.getCollectorUrl()) .httpClient(client) .build(); } retryDelay = new AtomicInteger(0); - batchSize = builder.batchSize; + batchSize = emitterConfig.getBatchSize(); - if (builder.eventStore != null) { - eventStore = builder.eventStore; + if (emitterConfig.getEventStore() != null) { + eventStore = emitterConfig.getEventStore(); } else { - eventStore = new InMemoryEventStore(builder.bufferCapacity); + eventStore = new InMemoryEventStore(emitterConfig.getBufferCapacity()); } - if (builder.fatalResponseCodes != null) { - fatalResponseCodes = builder.fatalResponseCodes; + if (emitterConfig.getFatalResponseCodes() != null) { + fatalResponseCodes = emitterConfig.getFatalResponseCodes(); } else { fatalResponseCodes = new ArrayList<>(); } - if (builder.requestExecutorService != null) { - executor = builder.requestExecutorService; + if (emitterConfig.getRequestExecutorService() != null) { + executor = emitterConfig.getRequestExecutorService(); } else { - executor = Executors.newScheduledThreadPool(builder.threadCount, new EmitterThreadFactory()); + executor = Executors.newScheduledThreadPool(emitterConfig.getThreadCount(), new EmitterThreadFactory()); } } + public BatchEmitter(NetworkConfiguration networkConfig) { + this(networkConfig, new EmitterConfiguration()); + } + /** * Adds a TrackerPayload to the EventStore buffer. * If the buffer is full, the payload will be lost. diff --git a/src/test/java/com/snowplowanalytics/snowplow/tracker/SnowplowTest.java b/src/test/java/com/snowplowanalytics/snowplow/tracker/SnowplowTest.java new file mode 100644 index 00000000..ebb0800d --- /dev/null +++ b/src/test/java/com/snowplowanalytics/snowplow/tracker/SnowplowTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2014-2022 Snowplow Analytics Ltd. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package com.snowplowanalytics.snowplow.tracker; + +import com.snowplowanalytics.snowplow.tracker.configuration.NetworkConfiguration; +import com.snowplowanalytics.snowplow.tracker.configuration.TrackerConfiguration; +import com.snowplowanalytics.snowplow.tracker.emitter.BatchEmitter; +import org.junit.After; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class SnowplowTest { + + @After + public void cleanUp(){ + Snowplow.reset(); + } + + @Test + public void createsAndRetrievesATracker() { + assertTrue(Snowplow.getTrackers().isEmpty()); + + Tracker tracker = Snowplow.createTracker("http://endpoint", "namespace", "appId"); + Tracker retrievedTracker = Snowplow.getTracker("namespace"); + + assertFalse(Snowplow.getTrackers().isEmpty()); + assertEquals(tracker, retrievedTracker); + assertEquals("namespace", tracker.getNamespace()); + assertEquals("appId", tracker.getAppId()); + assertTrue(tracker.getBase64Encoded()); + } + + @Test + public void preventsDuplicateNamespaces() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + Snowplow.createTracker("http://endpoint", "namespace", "appId"); + Snowplow.createTracker("http://endpoint2", "namespace", "appId2"); + }); + + assertEquals("Tracker with this namespace already exists.", exception.getMessage()); + } + + @Test + public void deletesStoredTracker() { + Snowplow.createTracker("http://endpoint", "namespace", "appId"); + boolean result = Snowplow.removeTracker("namespace"); + assertTrue(result); + + Tracker tracker = Snowplow.createTracker("http://endpoint", "namespace2", "appId"); + boolean result2 = Snowplow.removeTracker(tracker); + assertTrue(result2); + } + + @Test + public void hasDefaultTracker() { + assertNull(Snowplow.getDefaultTracker()); + + Tracker tracker = Snowplow.createTracker("http://endpoint", "namespace", "appId"); + assertEquals(tracker, Snowplow.getDefaultTracker()); + + Tracker tracker2 = Snowplow.createTracker("http://endpoint", "namespace2", "appId"); + assertEquals(tracker, Snowplow.getDefaultTracker()); + + Snowplow.setDefaultTracker(tracker2); + assertEquals(tracker2, Snowplow.getDefaultTracker()); + } + + @Test + public void registersATrackerMadeWithoutSnowplowClass() { + BatchEmitter emitter = BatchEmitter.builder().url("http://collector").build(); + Tracker tracker = new Tracker.TrackerBuilder(emitter, "namespace", "appId").build(); + + Snowplow.registerTracker(tracker); + assertEquals(tracker, Snowplow.getDefaultTracker()); + assertEquals(1, Snowplow.getTrackers().size()); + } + + @Test + public void createsTrackerFromConfigs() { + TrackerConfiguration trackerConfig = new TrackerConfiguration("namespace", "appId"); + NetworkConfiguration networkConfig = new NetworkConfiguration().collectorUrl("http://collector-endpoint"); + + Tracker tracker = Snowplow.createTracker(trackerConfig, networkConfig); + Tracker retrievedTracker = Snowplow.getTracker("namespace"); + + assertFalse(Snowplow.getTrackers().isEmpty()); + assertEquals(tracker, retrievedTracker); + assertEquals("namespace", tracker.getNamespace()); + assertEquals("appId", tracker.getAppId()); + assertTrue(tracker.getBase64Encoded()); + } +}