com.vwo.VWO Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vwo-java-sdk Show documentation
Show all versions of vwo-java-sdk Show documentation
Java library to initiate VWo instance for server side a/b testing
/**
* Copyright 2019-2021 Wingify Software Pvt. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.vwo;
import com.vwo.enums.GoalEnums;
import com.vwo.enums.LoggerMessagesEnums;
import com.vwo.models.BatchEventData;
import com.vwo.models.Settings;
import com.vwo.services.batch.BatchEventQueue;
import com.vwo.services.core.BucketingService;
import com.vwo.services.core.VariationDecider;
import com.vwo.services.integrations.HooksManager;
import com.vwo.services.integrations.IntegrationEventListener;
import com.vwo.services.settings.SettingFile;
import com.vwo.services.settings.SettingsFileUtil;
import com.vwo.services.settings.SettingsFileManager;
import com.vwo.services.api.ActivateCampaign;
import com.vwo.services.api.CampaignVariation;
import com.vwo.services.api.FeatureCampaign;
import com.vwo.services.api.Segmentation;
import com.vwo.services.api.TrackCampaign;
import com.vwo.enums.VWOEnums;
import com.vwo.logger.Logger;
import com.vwo.logger.VWOLogger;
import com.vwo.services.storage.Storage;
import java.util.HashMap;
import java.util.Map;
/**
* Main VWO class exposed to customers. It needs to be instantiated to access all the APIs.
*/
public class VWO {
final Storage.User userStorage;
final VWOLogger customLogger;
final VariationDecider variationDecider;
final GoalEnums.GOAL_TYPES goalTypeToTrack;
final Integer pollingInterval;
final String sdkKey;
private String settingFileString;
private SettingFile settingFile;
private BatchEventQueue batchEventQueue;
private boolean developmentMode;
private Map usageStats;
public static final class Enums extends VWOEnums {
}
public static final class AdditionalParams extends VWOAdditionalParams {
}
private static final Logger LOGGER = Logger.getLogger(VWO.class);
private VWO(
SettingFile settingFile,
String settingFileString,
Storage.User userStorage,
VariationDecider variationDecider,
VWOLogger customLogger,
boolean developmentMode,
GoalEnums.GOAL_TYPES goalTypeToTrack,
Integer pollingInterval,
String sdkKey,
BatchEventQueue batchEventQueue,
Map usageStats
) {
this.userStorage = userStorage;
this.settingFile = settingFile;
this.settingFileString = settingFileString;
this.customLogger = customLogger;
this.developmentMode = developmentMode;
this.variationDecider = variationDecider;
this.goalTypeToTrack = goalTypeToTrack;
this.pollingInterval = pollingInterval;
this.sdkKey = sdkKey;
this.batchEventQueue = batchEventQueue;
this.usageStats = usageStats;
if (this.pollingInterval != null && this.sdkKey != null) {
this.pollSettingsFile();
}
}
/**
* Poll settings file after every pollingInterval ms by spawning a new thread.
*/
private void pollSettingsFile() {
(new Thread(() -> {
while (true) {
try {
fetchAndUpdateSettings();
Thread.sleep(this.pollingInterval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
})).start();
}
/**
* Fetch settings file and update it on the instance in case settings differ from the previous fetched settings.
*/
private void fetchAndUpdateSettings() {
Settings settings = this.settingFile.getSettings();
String accountId = settings.getAccountId().toString();
Map loggingParams = new HashMap() {
{
put("accountID", accountId);
}
};
try {
String settingsFileString = this.getSettingsFile(accountId, this.sdkKey);
if (!settingsFileString.equals(this.settingFileString)) {
LOGGER.info(LoggerMessagesEnums.INFO_MESSAGES.VWO_SDK_INSTANCE_UPDATED.value(loggingParams));
updateSettingsFile(settingsFileString);
} else {
LOGGER.info(LoggerMessagesEnums.INFO_MESSAGES.SETTINGS_NOT_UPDATED.value());
}
LOGGER.info(LoggerMessagesEnums.INFO_MESSAGES.POLLED_SETTINGS_FILE.value(loggingParams));
} catch (Exception e) {
LOGGER.error(LoggerMessagesEnums.ERROR_MESSAGES.SETTINGS_FILE_POLLING_ERROR.value(loggingParams));
}
}
/**
* Update the settings-file on the instance so that latest settings could be used from next hit onwards.
*
* @param settingsFileString Stringified settings file.
*/
private void updateSettingsFile(String settingsFileString) {
this.settingFileString = settingsFileString;
this.settingFile = SettingsFileUtil.initializeSettingsFile(settingsFileString);
}
public SettingFile getSettingFile() {
return this.settingFile;
}
public String getSettingFileString() {
return this.settingFileString;
}
public Storage.User getUserStorage() {
return this.userStorage;
}
public VariationDecider getVariationDecider() {
return this.variationDecider;
}
public VWOLogger getCustomLogger() {
return this.customLogger;
}
public BatchEventQueue getBatchEventQueue() {
return this.batchEventQueue;
}
public boolean isDevelopmentMode() {
return this.developmentMode;
}
public Map getUsageStats() {
return this.usageStats;
}
public void setDevelopmentMode(boolean developmentMode) {
this.developmentMode = developmentMode;
}
/**
* Fetch the account settings file.
*
* @param accountID VWO application account-id.
* @param sdkKey Unique sdk-key
* @return Campaign settings
*/
public static String getSettingsFile(String accountID, String sdkKey) {
return SettingsFileManager.getSettingsFile(accountID, sdkKey, false);
}
/**
* Get variation and track conversion on VWO server for users falling in provided pre-segmentation.
*
* @param campaignKey Campaign key
* @param userId User ID
* @param additionalParams Any Additional params (customVariables, variationTargetingVariables)
* @return String variation name, or null if the user doesn't qualify to become a part of the campaign.
*/
public String activate(String campaignKey, String userId, VWOAdditionalParams additionalParams) {
additionalParams = additionalParams == null ? new VWO.AdditionalParams() : additionalParams;
return ActivateCampaign.activate(
campaignKey,
userId,
this.getSettingFile(),
this.getVariationDecider(),
this.isDevelopmentMode(),
this.batchEventQueue,
this.usageStats,
additionalParams.getCustomVariables(),
additionalParams.getVariationTargetingVariables(),
additionalParams.getShouldTrackReturningUser()
);
}
/**
* Get variation and track conversion on VWO server.
*
* @param campaignKey Campaign key
* @param userId User ID
* @return String variation name, or null if the user doesn't qualify to become a part of the campaign.
*/
public String activate(String campaignKey, String userId) {
return ActivateCampaign.activate(campaignKey, userId, this.getSettingFile(), this.getVariationDecider(), this.isDevelopmentMode(), this.batchEventQueue, this.usageStats, null, null, null);
}
/**
* Get variation name for users falling in provided pre-segmentation.
*
* @param campaignKey Campaign key
* @param userId User ID
* @param additionalParams Any Additional params (customVariables, variationTargetingVariables)
* @return Variation name
*/
public String getVariationName(String campaignKey, String userId, VWOAdditionalParams additionalParams) {
additionalParams = additionalParams == null ? new VWO.AdditionalParams() : additionalParams;
return CampaignVariation.getVariationName(
campaignKey,
userId,
this.getSettingFile(),
this.getVariationDecider(),
additionalParams.getCustomVariables(),
additionalParams.getVariationTargetingVariables()
);
}
/**
* Get variation name.
*
* @param campaignKey Campaign key
* @param userId User ID
* @return Variation name
*/
public String getVariationName(String campaignKey, String userId) {
return CampaignVariation.getVariationName(campaignKey, userId, this.getSettingFile(), this.getVariationDecider(), null, null);
}
/**
* Get variation, tracks conversion event and send to VWO server.
*
* @param campaignKey Campaign key or array of Strings containing campaign keys or null
* @param userId User ID
* @param goalIdentifier Goal key
* @param additionalParams Any Additional params (revenueValue, customVariables, variationTargetingVariables)
* @return Map containing the campaign name and their boolean status representing if tracked or not, and null if something went wrong.
*/
public Map track(Object campaignKey, String userId, String goalIdentifier, VWOAdditionalParams additionalParams) {
additionalParams = additionalParams == null ? new VWO.AdditionalParams() : additionalParams;
GoalEnums.GOAL_TYPES goalsToTrack = additionalParams.getGoalTypeToTrack() == null
? this.goalTypeToTrack
: additionalParams.getGoalTypeToTrack();
return TrackCampaign.trackGoal(
campaignKey,
userId,
goalIdentifier,
additionalParams.getRevenueValue(),
this.getSettingFile(),
this.getVariationDecider(),
this.isDevelopmentMode(),
this.batchEventQueue,
additionalParams.getCustomVariables(),
additionalParams.getVariationTargetingVariables(),
goalsToTrack,
additionalParams.getShouldTrackReturningUser()
);
}
public Map track(Object campaignKey, String userId, String goalIdentifier) {
return TrackCampaign.trackGoal(
campaignKey,
userId,
goalIdentifier,
null,
this.getSettingFile(),
this.getVariationDecider(),
this.isDevelopmentMode(),
this.batchEventQueue,
null,
null,
this.goalTypeToTrack,
null
);
}
/**
* Identifies whether the user became part of feature rollout/test or not.
*
* @param campaignKey Unique campaign test key
* @param userId ID assigned to a user
* @param additionalParams Any Additional params (customVariables, variationTargetingVariables)
* @return Boolean corresponding to whether user became part of feature.
*/
public boolean isFeatureEnabled(String campaignKey, String userId, VWOAdditionalParams additionalParams) {
additionalParams = additionalParams == null ? new VWO.AdditionalParams() : additionalParams;
return FeatureCampaign.isFeatureEnabled(
campaignKey,
userId,
this.getSettingFile(),
this.getVariationDecider(),
this.isDevelopmentMode(),
this.batchEventQueue,
this.usageStats,
additionalParams.getCustomVariables(),
additionalParams.getVariationTargetingVariables(),
additionalParams.getShouldTrackReturningUser()
);
}
/**
* Identifies whether the user became part of feature rollout/test or not for users falling in provided pre-segmentation.
*
* @param campaignKey Unique campaign test key
* @param userId ID assigned to a user
* @return Boolean corresponding to whether user became part of feature.
*/
public boolean isFeatureEnabled(String campaignKey, String userId) {
return FeatureCampaign.isFeatureEnabled(campaignKey, userId, this.getSettingFile(), this.getVariationDecider(), this.isDevelopmentMode(), this.batchEventQueue, this.usageStats, null, null, null);
}
/**
* Gets the feature variable corresponding to the variable_key passed.
*
* @param campaignKey Unique campaign test key
* @param userId ID assigned to a user
* @param variableKey Variable name/key
* @param additionalParams Any Additional params (customVariables, variationTargetingVariables)
* @return If variation is assigned then string variable corresponding to variation assigned otherwise null
*/
public Object getFeatureVariableValue(String campaignKey, String variableKey, String userId, VWOAdditionalParams additionalParams) {
additionalParams = additionalParams == null ? new VWO.AdditionalParams() : additionalParams;
return FeatureCampaign.getFeatureVariable(
campaignKey,
userId,
variableKey,
null,
this.getSettingFile(),
this.getVariationDecider(),
additionalParams.getCustomVariables(),
additionalParams.getVariationTargetingVariables()
);
}
/**
* Gets the feature variable corresponding to the variable_key passed for users falling in provided pre-segmentation.
*
* @param campaignKey Unique campaign test key
* @param variableKey Variable name/key
* @param userId ID assigned to a user
* @return If variation is assigned then string variable corresponding to variation assigned otherwise null
*/
public Object getFeatureVariableValue(String campaignKey, String variableKey, String userId) {
return FeatureCampaign.getFeatureVariable(campaignKey, userId, variableKey, null, this.getSettingFile(), this.getVariationDecider(), null, null);
}
/**
* Pushes the tag key and value for a user to be used in post segmentation.
*
* @param tagKey Tag name
* @param tagValue Tag value
* @param userId ID assigned to a user
* @return Boolean representing if the tag was pushed or not
*/
public boolean push(String tagKey, String tagValue, String userId) {
return Segmentation.pushCustomDimension(this.getSettingFile(), tagKey, tagValue, userId, this.batchEventQueue, this.isDevelopmentMode());
}
/**
* Manually flush impression events to VWO which are queued in batch queue as per batchEvents config.
*
* @return Boolean representing if the events are flushed or not
*/
public boolean flushEvents() {
int accountId = this.settingFile.getSettings().getAccountId();
if (this.batchEventQueue != null) {
return this.batchEventQueue.flushAndClearInterval();
} else {
LOGGER.debug(LoggerMessagesEnums.DEBUG_MESSAGES.NO_BATCH_QUEUE.value(new HashMap() {
{
put("accountId", String.valueOf(accountId));
}
}));
return false;
}
}
/**
* Fetch latest settings-file and update so that vwoClientInstance could use latest settings.
* Helpful especially when using webhooks
*
* @param accountId VWO application account-id.
* @param sdkKey Unique sdk-key
*/
public void getAndUpdateSettingsFile(String accountId, String sdkKey) {
String updatedSettings = SettingsFileManager.getSettingsFile(accountId, sdkKey, true);
if (updatedSettings != null) {
this.updateSettingsFile(updatedSettings);
}
}
// /**
// * Gets the feature details for a campaign.
// *
// * @param campaignKey Unique campaign test key
// * @return If variation is assigned then string variable corresponding to variation assigned otherwise null
// */
// public List getFeatureDetails(String campaignKey) {
// return FeatureCampaign.getFeatureDetails(campaignKey, this.getSettingFile());
// }
/**
* Creates builder instance.`
*
* @param settingFile - Setting string
* @return - Builder instance
*/
public static Builder launch(String settingFile) {
try {
return new Builder().withSettingFile(settingFile);
} catch (Exception e) {
LOGGER.error(LoggerMessagesEnums.ERROR_MESSAGES.GENERIC_ERROR.value(), e.getStackTrace());
}
return null;
}
public static class Builder {
private SettingFile settingFile;
private Storage.User userStorage;
private VariationDecider variationDecider;
private String settingFileString;
private BucketingService bucketingService;
private VWOLogger customLogger;
private boolean developmentMode;
private GoalEnums.GOAL_TYPES goalTypeToTrack = GoalEnums.GOAL_TYPES.ALL;
private Boolean shouldTrackReturningUser = false;
private Integer pollingInterval;
private String sdkKey;
private BatchEventData batchEvents;
private BatchEventQueue batchEventsQueue;
private IntegrationEventListener integrations;
private Map usageStats = new HashMap(){};
/**
* Pass the campaign settings file.
*
* @param settingFileString JSON stringified settings.
* @return Builder instance
*/
private Builder withSettingFile(String settingFileString) {
this.settingFileString = settingFileString;
return this;
}
/**
* Add Polling Interval.
*
* @param pollingInterval Polling interval in ms
* @return Builder instance
*/
public Builder withPollingInterval(Integer pollingInterval) {
this.pollingInterval = pollingInterval;
usageStats.put("pi", 1);
return this;
}
/**
* Add SDK key for polling.
*
* @param sdkKey SDK key used to fetch settings file incase of polling.
* @return Builder instance
*/
public Builder withSdkKey(String sdkKey) {
this.sdkKey = sdkKey;
return this;
}
/**
* Custom user storage instance.
*
* @param userStorage Storage.User class instance
* @return Builder instance
*/
public Builder withUserStorage(Storage.User userStorage) {
this.userStorage = userStorage;
usageStats.put("ss", 1);
return this;
}
/**
* Toggle development mode.
*
* @param developmentMode Boolean value specifying development mode is on ir off
* @return Builder instance
*/
public Builder withDevelopmentMode(boolean developmentMode) {
this.developmentMode = developmentMode;
return this;
}
/**
* Custom logger.
*
* @param customLogger VWOLogger instance
* @return Builder instance
*/
public Builder withCustomLogger(VWOLogger customLogger) {
this.customLogger = customLogger;
usageStats.put("cl", 1);
if (!VWOLogger.level.equals(VWOEnums.LOGGER_LEVEL.ERROR.value())) {
usageStats.put("ll", 1);
}
return this;
}
/**
* Notify whether the goal should be tracked again if its already being tracked.
*
* @param value true if goal should be tracked every time.
* @return Builder instance
*/
public Builder withGoalTypeToTrack(GoalEnums.GOAL_TYPES value) {
this.goalTypeToTrack = value;
usageStats.put("gt", 1);
return this;
}
/**
* Notify whether the goal should be tracked again if its already being tracked.
*
* @param value true if goal should be tracked every time.
* @return Builder instance
*/
public Builder withShouldTrackReturningUser(boolean value) {
this.shouldTrackReturningUser = value;
if (shouldTrackReturningUser) {
usageStats.put("tr", 1);
}
return this;
}
public Builder withBatchEvents(BatchEventData batchEvents) {
this.batchEvents = batchEvents;
usageStats.put("eb", 1);
return this;
}
public Builder withIntegrations(IntegrationEventListener integrations) {
this.integrations = integrations;
usageStats.put("ig", 1);
return this;
}
/**
* Creates a new VWO instance.
*
* @return VWO instance
*/
public VWO build() {
// Init logger at start.
Logger.init(this.customLogger);
this.initializeDefaults();
return this.createVWOInstance();
}
private void initializeDefaults() {
this.settingFile = SettingsFileUtil.initializeSettingsFile(this.settingFileString);
if (this.pollingInterval != null) {
if (this.sdkKey != null) {
LOGGER.debug(LoggerMessagesEnums.DEBUG_MESSAGES.REGISTERED_POLLING_INTERVAL.value(new HashMap() {
{
put("pollingInterval", pollingInterval.toString());
}
}));
} else {
LOGGER.error(LoggerMessagesEnums.ERROR_MESSAGES.MISSING_POLLING_SDK_KEY.value());
}
}
this.bucketingService = new BucketingService();
this.variationDecider = new VariationDecider(bucketingService, userStorage, shouldTrackReturningUser, new HooksManager(this.integrations),
settingFile.getSettings().getAccountId());
this.developmentMode = this.developmentMode || false;
if (developmentMode) {
usageStats.clear();
}
if (this.batchEvents != null) {
batchEventsQueue = new BatchEventQueue(this.batchEvents, settingFile.getSettings().getSdkKey(), settingFile.getSettings().getAccountId(), this.developmentMode, this.usageStats);
}
}
private VWO createVWOInstance() {
VWO vwoInstance = new VWO(
this.settingFile,
this.settingFileString,
this.userStorage,
this.variationDecider,
this.customLogger,
this.developmentMode,
this.goalTypeToTrack,
this.pollingInterval,
this.sdkKey,
this.batchEventsQueue,
this.usageStats
);
if (vwoInstance != null) {
LOGGER.debug(LoggerMessagesEnums.DEBUG_MESSAGES.SDK_INITIALIZED.value());
}
return vwoInstance;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy