All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.rtr.alchemy.identities.Identity Maven / Gradle / Ivy

package io.rtr.alchemy.identities;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutionException;

import javax.annotation.Nonnull;

/** Identifies a unique entity whose hash code is used for treatments allocation */
public abstract class Identity {
    protected static final Set EMPTY = Collections.emptySet();

    /** Get a list of possible attribute values that can be returned by this identity */
    public static  Set getSupportedAttributes(Class clazz) {
        try {
            return ATTRIBUTES_CACHE.get(clazz);
        } catch (final ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * generates a hash code used to assign identity to treatment
     *
     * @param seed a seed value to randomize the resulting hash from experiment to experiment for
     *     the same identity
     * @param hashAttributes a set of attributes that should be used to compute the hash code
     * @param attributes a map of attribute values
     */
    public long computeHash(int seed, Set hashAttributes, AttributesMap attributes) {
        final IdentityBuilder builder = IdentityBuilder.seed(seed);
        final Iterable names =
                hashAttributes.isEmpty() ? attributes.keySet() : hashAttributes;

        for (String name : names) {
            final Class type = attributes.getType(name);

            if (type == String.class) {
                builder.putString(attributes.getString(name));
            } else if (type == Long.class) {
                builder.putLong(attributes.getNumber(name));
            } else if (type == Boolean.class) {
                builder.putBoolean(attributes.getBoolean(name));
            }
        }

        return builder.hash();
    }

    /** generates a list of attributes that describe this identity for filtering */
    public abstract AttributesMap computeAttributes();

    /** Convenience method for getting an identity builder given a seed */
    protected IdentityBuilder identity(int seed) {
        return IdentityBuilder.seed(seed);
    }

    /** Convenience method for getting an attributes map builder */
    protected AttributesMap.Builder attributes() {
        return AttributesMap.newBuilder();
    }

    private static final LoadingCache, Set> ATTRIBUTES_CACHE =
            CacheBuilder.newBuilder()
                    .build(
                            new CacheLoader<>() {
                                @Override
                                public Set load(@Nonnull Class clazz) throws Exception {
                                    final Attributes annotation =
                                            clazz.getAnnotation(Attributes.class);
                                    if (annotation == null) {
                                        return EMPTY;
                                    }

                                    final Set result = new HashSet<>();
                                    Collections.addAll(result, annotation.value());

                                    for (final Class identity :
                                            annotation.identities()) {
                                        result.addAll(ATTRIBUTES_CACHE.get(identity));
                                    }

                                    return result;
                                }
                            });
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy