@@ -209,18 +209,15 @@ Variation activate(@Nonnull ProjectConfig projectConfig,
209209 logger .info ("Not activating user \" {}\" for experiment \" {}\" ." , userId , experiment .getKey ());
210210 return null ;
211211 }
212- // determine whether all the given attributes are present in the project config. If not, filter out the unknown
213- // attributes.
214- Map <String , ?> filteredAttributes = filterAttributes (projectConfig , attributes );
215-
212+ Map <String , ?> copiedAttributes = copyAttributes (attributes );
216213 // bucket the user to the given experiment and dispatch an impression event
217- Variation variation = decisionService .getVariation (experiment , userId , filteredAttributes );
214+ Variation variation = decisionService .getVariation (experiment , userId , copiedAttributes );
218215 if (variation == null ) {
219216 logger .info ("Not activating user \" {}\" for experiment \" {}\" ." , userId , experiment .getKey ());
220217 return null ;
221218 }
222219
223- sendImpression (projectConfig , experiment , userId , filteredAttributes , variation );
220+ sendImpression (projectConfig , experiment , userId , copiedAttributes , variation );
224221
225222 return variation ;
226223 }
@@ -292,6 +289,7 @@ public void track(@Nonnull String eventName,
292289 }
293290
294291 ProjectConfig currentConfig = getProjectConfig ();
292+ Map <String , ?> copiedAttributes = copyAttributes (attributes );
295293
296294 EventType eventType = currentConfig .getEventTypeForName (eventName , errorHandler );
297295 if (eventType == null ) {
@@ -300,20 +298,15 @@ public void track(@Nonnull String eventName,
300298 return ;
301299 }
302300
303- // determine whether all the given attributes are present in the project config. If not, filter out the unknown
304- // attributes.
305- Map <String , ?> filteredAttributes = filterAttributes (currentConfig , attributes );
306-
307301 if (eventTags == null ) {
308302 logger .warn ("Event tags is null when non-null was expected. Defaulting to an empty event tags map." );
309- eventTags = Collections .<String , String >emptyMap ();
310303 }
311304
312305 List <Experiment > experimentsForEvent = projectConfig .getExperimentsForEventKey (eventName );
313306 Map <Experiment , Variation > experimentVariationMap = new HashMap <Experiment , Variation >(experimentsForEvent .size ());
314307 for (Experiment experiment : experimentsForEvent ) {
315308 if (experiment .isRunning ()) {
316- Variation variation = decisionService .getVariation (experiment , userId , filteredAttributes );
309+ Variation variation = decisionService .getVariation (experiment , userId , copiedAttributes );
317310 if (variation != null ) {
318311 experimentVariationMap .put (experiment , variation );
319312 }
@@ -331,7 +324,7 @@ public void track(@Nonnull String eventName,
331324 userId ,
332325 eventType .getId (),
333326 eventType .getKey (),
334- filteredAttributes ,
327+ copiedAttributes ,
335328 eventTags );
336329
337330 if (conversionEvent == null ) {
@@ -354,7 +347,7 @@ public void track(@Nonnull String eventName,
354347 }
355348
356349 notificationCenter .sendNotifications (NotificationCenter .NotificationType .Track , eventName , userId ,
357- filteredAttributes , eventTags , conversionEvent );
350+ copiedAttributes , eventTags , conversionEvent );
358351 }
359352
360353 //======== FeatureFlag APIs ========//
@@ -406,17 +399,15 @@ else if (userId == null) {
406399 logger .info ("No feature flag was found for key \" {}\" ." , featureKey );
407400 return false ;
408401 }
409-
410- Map <String , ?> filteredAttributes = filterAttributes (projectConfig , attributes );
411-
412- FeatureDecision featureDecision = decisionService .getVariationForFeature (featureFlag , userId , filteredAttributes );
402+ Map <String , ?> copiedAttributes = copyAttributes (attributes );
403+ FeatureDecision featureDecision = decisionService .getVariationForFeature (featureFlag , userId , copiedAttributes );
413404 if (featureDecision .variation != null ) {
414405 if (featureDecision .decisionSource .equals (FeatureDecision .DecisionSource .EXPERIMENT )) {
415406 sendImpression (
416407 projectConfig ,
417408 featureDecision .experiment ,
418409 userId ,
419- filteredAttributes ,
410+ copiedAttributes ,
420411 featureDecision .variation );
421412 } else {
422413 logger .info ("The user \" {}\" is not included in an experiment for feature \" {}\" ." ,
@@ -655,8 +646,9 @@ else if (userId == null) {
655646 }
656647
657648 String variableValue = variable .getDefaultValue ();
649+ Map <String , ?> copiedAttributes = copyAttributes (attributes );
658650
659- FeatureDecision featureDecision = decisionService .getVariationForFeature (featureFlag , userId , attributes );
651+ FeatureDecision featureDecision = decisionService .getVariationForFeature (featureFlag , userId , copiedAttributes );
660652 if (featureDecision .variation != null ) {
661653 LiveVariableUsageInstance liveVariableUsageInstance =
662654 featureDecision .variation .getVariableIdToLiveVariableUsageInstanceMap ().get (variable .getId ());
@@ -716,10 +708,9 @@ Variation getVariation(@Nonnull Experiment experiment,
716708 Variation getVariation (@ Nonnull Experiment experiment ,
717709 @ Nonnull String userId ,
718710 @ Nonnull Map <String , ?> attributes ) throws UnknownExperimentException {
711+ Map <String , ?> copiedAttributes = copyAttributes (attributes );
719712
720- Map <String , ?> filteredAttributes = filterAttributes (projectConfig , attributes );
721-
722- return decisionService .getVariation (experiment , userId , filteredAttributes );
713+ return decisionService .getVariation (experiment , userId , copiedAttributes );
723714 }
724715
725716 public @ Nullable
@@ -754,10 +745,8 @@ Variation getVariation(@Nonnull String experimentKey,
754745 // if we're unable to retrieve the associated experiment, return null
755746 return null ;
756747 }
757-
758- Map <String , ?> filteredAttributes = filterAttributes (projectConfig , attributes );
759-
760- return decisionService .getVariation (experiment ,userId ,filteredAttributes );
748+ Map <String , ?> copiedAttributes = copyAttributes (attributes );
749+ return decisionService .getVariation (experiment , userId , copiedAttributes );
761750 }
762751
763752 /**
@@ -817,50 +806,6 @@ public UserProfileService getUserProfileService() {
817806 }
818807
819808 //======== Helper methods ========//
820-
821- /**
822- * Helper method to verify that the given attributes map contains only keys that are present in the
823- * {@link ProjectConfig}.
824- *
825- * @param projectConfig the current project config
826- * @param attributes the attributes map to validate and potentially filter. Attributes which starts with reserved key
827- * {@link ProjectConfig#RESERVED_ATTRIBUTE_PREFIX} are kept.
828- * @return the filtered attributes map (containing only attributes that are present in the project config) or an
829- * empty map if a null attributes object is passed in
830- */
831- private Map <String , ?> filterAttributes (@ Nonnull ProjectConfig projectConfig ,
832- @ Nonnull Map <String , ?> attributes ) {
833- if (attributes == null ) {
834- logger .warn ("Attributes is null when non-null was expected. Defaulting to an empty attributes map." );
835- return Collections .<String , String >emptyMap ();
836- }
837-
838- // List of attribute keys
839- List <String > unknownAttributes = null ;
840-
841- Map <String , Attribute > attributeKeyMapping = projectConfig .getAttributeKeyMapping ();
842- for (Map .Entry <String , ?> attribute : attributes .entrySet ()) {
843- if (!attributeKeyMapping .containsKey (attribute .getKey ()) &&
844- !attribute .getKey ().startsWith (ProjectConfig .RESERVED_ATTRIBUTE_PREFIX )) {
845- if (unknownAttributes == null ) {
846- unknownAttributes = new ArrayList <String >();
847- }
848- unknownAttributes .add (attribute .getKey ());
849- }
850- }
851-
852- if (unknownAttributes != null ) {
853- logger .warn ("Attribute(s) {} not in the datafile." , unknownAttributes );
854- // make a copy of the passed through attributes, then remove the unknown list
855- attributes = new HashMap <>(attributes );
856- for (String unknownAttribute : unknownAttributes ) {
857- attributes .remove (unknownAttribute );
858- }
859- }
860-
861- return attributes ;
862- }
863-
864809 /**
865810 * Helper function to check that the provided userId is valid
866811 *
@@ -880,6 +825,20 @@ private boolean validateUserId(String userId) {
880825 return true ;
881826 }
882827
828+ /**
829+ * Helper function to check that the provided attributes are null if not than it returns a copy
830+ *
831+ * @param attributes the attributes map being validated
832+ * @return copy of attributes
833+ */
834+ private Map <String , ?> copyAttributes (Map <String , ?> attributes ) {
835+ Map <String , ?> copiedAttributes = null ;
836+ if (attributes != null ) {
837+ copiedAttributes = new HashMap <>(attributes );
838+ }
839+ return copiedAttributes ;
840+ }
841+
883842 //======== Builder ========//
884843
885844 public static Builder builder (@ Nonnull String datafile ,
0 commit comments